Table of Contents
About The Project
Hats Protocol is a protocol for DAO-native roles and credentials that supports revocable delegation of authority and responsibility.
Hats are represented on-chain by non-transferable tokens that conform to the ERC1155 interface. An address with a balance of a given Hat token "wears" that hat, granting them the responsibilities and authorities that have been assigned to the Hat by the DAO.
Deployments
For information on Hats Protocol versions and deployments, see Releases.
Security Audits
This project has received two security audits, listed below. See the audits directory for the detailed reports.
Auditor | Report Date | Review Commit Hash | Notes |
---|---|---|---|
Trust Security | Feb 23, 2023 | 60f07df | Report also includes findings from Hats Protocol audit |
Sherlock | May 3, 2023 | fafcfd | Report also includes findings from Hats Protocol audit |
Contributing
See CONTRIBUTING.md for details on how to contribute.
Hats Protocol Docs
Table of Contents
- Authorities in Hats Protocol
- Hats Logic
- ERC1155 Compatibility
- Wearing a Hat
- Hat Admins
- Addressable Hat Ids
- Eligibility
- Toggle
- Hat Mutability
- Hat Image URIs
- Creating a Hat
- Minting a Hat
- Transferring a Hat
- Hat Tree Grafting
- Renouncing a Hat
Authorities in Hats Protocol
One way to think about a Hat is as a primitive that creates a substrate onto which a DAO can attach authorities (e.g., access rights) and responsibilities via other tools (e.g., token-gating platforms).
Hats Protocol itself does not define mechanisms for how such authorities and responsibilities are associated with a Hat. All such associations are created external to the protocol.
Here are a few examples of how a DAO might confer authorities and responsibilities to a Hat:
Authority | How is it attached to the Hat? |
---|---|
Signer on a multisig | Using the Hat's ERC1155-similar token as a condition for membership in a Metropolis Pod |
Admin of the DAO's Github repo | Using the Hat's ERC1155-similar token as a condition for access via Lit Protocol |
Leadership of a working group | A social expectation |
In each case, the DAO uses a separate tool to attach the authority to the Hat.
Hats is designed to be highly composable -- it will work with any tool, application, or protocol that can interact with the ERC1155 interface. Further, it allows any number of such authorities or responsibilities to be attached to a single Hat, which greatly simplifies the process for DAOs of revoking those authorities as well as the process of role handoff.
Exception: Hat Admins
Hat admins are the one (very important!) exception to the rule that authorities are external to the Hats Protocol. Refer to the Admins section below for more details.
ERC1155 Compatibility
Hats Protocol conforms fully to the ERC1155 interface. All external functions required by the ERC1155 standard are exposed by Hats Protocol. This is how Hats can work out of the box with existing token-gating applications.
However, Hats Protocol is not fully compliant with the ERC1155 standard. Since Hats are not transferable by their owners (aka "wearers"), there is little need for safe transfers and the ERC1155TokenReceiver
logic. Developers building on top of Hats Protocol should note that mints and transfers of Hats will not, for example, include calls to onERC1155Received
.
To avoid confusion, Hats Protocol does not claim to be ERC1155-compliant. Instead, we say that Hats Protocol has "ERC1155-similar" tokens. When referring specifically to the ERC1155 interface, however, we do say that Hats Protocol conforms fully.
Hats Logic
Each Hat has several properties:
id
- the integer identifier for the Hat, which also serves as the ERC1155-similar token id (see three paragraphs below)details
- metadata about the Hat; such as a name, description, and other properties like roles and responsibilities associated with the Hat. Should not exceed 7,000 characters.maxSupply
- the maximum number of addresses that can wear the Hat at onceadmin
- the Hat that controls who can wear the Hateligibility
- the address that controls eligibility criteria and whether a given wearer of the Hat is in good standingtoggle
- the address that controls whether the Hat is activemutable
- whether the hat's properties can be changed by the adminimageURI
- the URI for the image used in the Hat's ERC1155-similar token. Should not exceed 7,000 characters.
For more information on each property, refer to the detailed sections below.
Wearing a Hat
The wearer of a given Hat is assigned the authorities and responsibilities associated with the Hat.
A wearer's status relating to a given Hat is determined by three factors. All three must be true.
- Whether their address has a balance (of 1) of the Hat's token
- Whether the Hat is active (see the Toggle section for more detail)
- Whether they are eligible (see the Eligibility section for more detail)
All of these factors are reflected in the Hats.balanceOf
function, which will return 0
if any of the factors are false.
Any address can wear a Hat, including:
- Externally Owned Accounts (EOAs)
- Logic contracts (i.e., contracts with explicit logic codified within functions), or
- Governance contracts (e.g., DAOs, multisigs, etc.)
Hat Admins
The admin of every Hat is another Hat. This means that the authority to perform admin functions for a given Hat is assigned to the wearer of its admin Hat.
The scope of authority for a Hat's admin is to determine who can wear it. This is reflected in the ability to create the Hat and to mint or (for mutable Hats) transfer the Hat's token.
Hatter Contracts
Logic contracts that serve as admins are informally known as "hatter" contracts. These are contracts that implement specific logic or rules. The admin of a hatter contract is the true admin, but has delegated said admin authority to the logic embedded in the hatter.
Hatter contract logic is a wide design space for DAOs. Here are some examples of hatter logic:
- Wearer eligibility - Enforce certain requirements that prospective wearers must meet in order to wear a given Hat, such as membership in a DAO or holding some token(s).
- Wearer staking - One particularly important type of eligibility requirement is staking tokens, DAO shares, or some other asset as a bond that could be slashed if the wearer is not a good steward of the accountabilities associated with the Hat, or does not follow through on its associated responsibilities.
- Hat creation - Allow certain addresses -- such as members of a DAO -- to create Hats that are then admin'd by the DAO.
- Hat minting - Allow certain addresses -- such as members of a DAO -- to mint Hat tokens. Together with the above, a DAO could in this way enable its members to create and wear a certain type of Hat permissionlessly. This would be especially if using Hats to facilitate role clarity and legibility.
Hat Trees
The ability of a Hat to be an admin of other Hats creates the possibility for a "tree" of Hats, a structure of Hats serving as admins of other Hats. This is useful because it enables a DAO to snip off, but not destroy, a rogue branch by revoking the offending Hat. It could then re-assign that admin Hat to another wearer.
Within a given branch of a hat tree, Hats closer to the root of the tree have admin authorities for Hats further down the branch. This is consistent with the direction of delegation of authority for DAOs, and combats the tendency for accountability to dilute as delegated authorities reach the edges of a network.
Tophats
Tophats are the one exception to the rule that a Hat's admin must be another hat. A Tophat is a Hat that serves as its own admin.
The root of a Hat tree is always a Tophat. Typically, a DAO will wear the Tophat that serves as admin for the tree of Hats related to the DAO's operations.
Addressable Hat Ids
Hat ids are uint256 bitmaps that create an "address" — more like an web or IP address than an Ethereum address — that includes information about the entire branch of admins for a given hat.
The 32 bytes of a hat's id are structured as follows:
- The first 4 bytes are reserved for the top hat id. Since top hat ids are unique across a given deployment of Hats Protocol, we can also think of them as the top level "domain" for a hat tree.
- Each of the next chunks of 16 bits refers to a single "Hat Level".
This means there are 15 total hat levels, beginning with the top hat at level 0 and going up to level 14. A hat at level 6 will have 6 admins in its branch of the tree, and therefore its id will have non-zero values at levels 0-5 as well as its own level. Since these values correspond to its admins, all that is needed to know which hats have admin authorities over a given hat is to know that given hat's id.
Hat Tree Space
A hat tree can have up to 14 levels, plus the top hat (tree root). Within those 14 levels are 224 bits of address space (remember, one level contains 16 bits of space), so the maximum number of hats in a single hat tree is $2^{224} + 1 \approx ~2.696 * 10^{67}$, or well beyond the number of stars in the universe.
Displaying Hat Ids
It is recommended for front ends to instead convert hat ids to hexadecimal, revealing the values of the bytes — and therefore the hat levels — directly.
For example, instead of a hat id looking like this under base 10: 26960769438260605603848134863118277618512635038780455604427388092416
...under hexadecimal it would look like this: 0x0000000100020003000000000000000000000000000000000000000000000000
In this second version, you can see that this hat is...
- a level 2 hat
- is in the first hat tree (top hat id = 1)
- is the third hat created at level 2 within this tree
- admin'd by the second hat created at level 1 within this tree
We can also prettify this even further by separating hat levels with periods, a la IP addresses:
0x00000001.0002.0003.0000.0000.0000.0000.0000.0000.0000.0000.0000.0000.0000.0000
Eligibility
Eligibility modules have authority to rule on the a) eligibility and b) good standing of wearer(s) of a given Hat.
Wearer Eligibility (A) determines whether a given address is eligible to wear the Hat. This applies both before and while the address wears the Hat. Consider the following scenarios for a given address:
Eligible | Not Eligible | |
---|---|---|
Doesn't wear the Hat | Hat can be minted to the address | Hat cannot be minted to the address |
Currently wears the Hat | Keeps wearing the Hat | The Hat is revoked |
When a Hat is revoked, its token is burned.
Wearer Standing (B) determines whether a given address is in good or bad standing. Standing is stored on-chain in Hats.sol
to facilitate accountability.
For example, a hatter contract implementing staking logic could slash a wearer's stake if they are placed in bad standing by the eligibility module.
An address placed in bad standing by a Hat's eligibility module automatically loses eligibility for that Hat. Note, though, that ineligibility does necessarily imply bad standing; it is possible for an address may be ineligible but in good standing.
Any address can serve as an eligibility module for a given Hat. Hats Protocol supports two categories of eligibility modules:
- Mechanistic eligibility are logic contracts that implement the
IHatsEligibility
interface, which enables the Hats contract to pull wearer standing by callingcheckWearerStanding
from within theHats.balanceOf
function. Mechanistic eligibility enables instantaneous revocation based on pre-defined triggers. - Humanistic eligibility are either EOAs or governance contracts. To revoke a Hat, humanistic eligibility must push updates to the Hats contract by calling
Hats.ruleOHatWearerStanding
.
Unlike admins, eligibility modules are explicitly set as addresses, not Hats. This is to avoid long, potentially illegible, chains of revocation authority that can affect wearer penalties (such as slashed stake).
Toggle
Toggle contracts have authority to switch the hat.active
status of a Hat, such as from active
to inactive
. When a Hat is inactive, it does not have any wearers (i.e., the balance of its previous wearers' is changed to 0).
Any address can serve as a Hat's toggle. As with eligibility modules, Hats Protocol supports two categories of toggle modules:
- Mechanistic toggles are logic contracts that implement the
IHatsToggle
interface, which enables the Hats contract to pull a Hat's active status by callingcheckToggle
from within theHats.balanceOf
function. Mechanistic toggle enable instantaneous deactivation (or reactivation) based on pre-defined logic, such as timestamps ("this Hat expires at the end of the year"). - Humanistic toggles are either EOAs or governance contracts. To deactivate (or reactivate) a Hat, humanistic toggles must push updates to the Hats contract by calling
Hats.toggleHatStatus
.
Unlike admins, toggle modules are explicitly set as addresses, not Hats.
Hat Mutability
In some cases, a Hat's properties should be immutable to give everybody (particularly the wearer(s)) maximal confidence in what they are signing up for. But this certainty comes at the expense of flexibility, which is often valuable for DAOs as they evolve and learn more about what their various roles are all about. With this trade-off in mind, Hats can be created as either mutable or immutable.
An immutable Hat cannot be changed at all once it has been created. A mutable Hat can be changed after it has been created. Only its admin(s) can make the change.
Changes are allowed to the following Hat properties:
details
maxSupply
- as long as the new maxSupply is not less than the current supplyeligibility
toggle
mutable
- this is a one-way changeimageURI
Additionally, mutable hats can be transferred by their admins to a different wearer. Immutable hats cannot be transferred.
TopHat Exception
The only exception to the above mutability rules is for tophats, which despite being immutable are allowed to change their own details
and imageURI
(but not other properties).
Note that this only includes non-linked tophats; a tophat that has been linked (aka grafted) onto another hat tree is no longer considered a tophat, and therefore is subject to the same mutability rules as other hats.
Hat Image URIs
Like any other NFT, Hats have images. The image for a given Hat is determined by the following logic:
- If the Hat's
imageURI
property is set, use that - If the Hat's
imageURI
property is not set, then use theimageURI
of the Hat's admin Hat - If the admin Hat's
imageURI
property is not set, then use theimageURI
of that Hat's admin - Repeat (3) until you find an
imageURI
that is set - If no set
imageURI
is found within the original Hat's hat tree (including the Tophat), then use theglobalImageURI
set in the Hats Protocol contract
This logic creates flexibility for DAOs to efficiently customize images for their Hats, while keeping images as optional.
Creating a Hat
The creator of a Hat must be its admin. In other words, the admin of a Hat must be the msg.sender
of the Hats.createHat
function call. Though remember, by delegating its authority to a hatter contract, an admin can enable eligible others to create Hats based on whatever logic it desires.
Creating a Tophat (a Hat that serves as its own admin) requires a special function mintTophat
, which creates a new Hat, sets that Hat as its own admin, and then mints its token to a _target
. Any address wanting to create a Hat that is not already wearing an admin Hat of some kind must first create a Tophat with itself as the wearer.
Batch Creation
In some scenarios, a DAO may want to create many Hats at once -- including an entire hat tree -- at once. This is particularly useful when setting up an initial structure for a DAO or working group (e.g., from a Hats template) or when forking an existing Hats structure from a template.
Enabling this latter forking/exit scenario is an important protection for Hat wearers against potential abuse of power by their DAO.
To create a batch of Hats, a DAO can call the Hats.batchCreateHats()
function. This function takes arrays as its arguments, from which it constructs multiple Hats. As long as each of these Hats is part of the same tree of Hats — i.e., they either have the same existing Hat or any of the newly created Hats as admin(s) — they can all be created together.
Minting a Hat
Only a Hat's admin can mint its token to a wearer.
To mint a Hat, the Hat must be active, its max supply must not have already been reached, the target wearer must not already wear the Hat, and the target wearer must be eligible for the Hat.
A Hat's admin can mint its token individually by calling Hats.mintHat
.
Batch Minting
An admin can also mint multiple Hats by calling Hats.batchMintHats
. This enables an admin to mint instances of the same hat to multiple wearers, to mint several Hats at once, or even to mint an entire Hats tree it just created.
Transferring a Hat
Only a Hat's admin can transfer its token(s) to new wearer(s).
Unlike typical tokens, the wearer of a Hat cannot transfer the Hat to another wallet. This is because the authorities and responsibilities associated with a Hat are delegated to, not owned by, the wearer.
As a result, there is no need for safe transfers (transfers which check whether the recipient supports ERC1155) or to pass data to recipient on1155Received
or onERC1155BatchReceived
hooks.
For these reasons, in Hats Protocol, the standard ERC1155 transfer functions — safeTransferFrom
and safeBatchTransferFrom
are disabled and will always revert. Similarly, token approvals are not required and setApprovalForAll
will always revert.
As a replacement, Hats can be transferred by admins via Hats.transferHat
, which emits the ERC1155 standard event TransferSingle
. Transfer recipients must not already be wearing the hat, and must be eligible to wear the hat.
With the exception of tophats — which can always transfer themselves — only mutable Hats can be transferred. Inactive Hats cannot be transferred.
Hat Tree Grafting
Not all Hats trees will unfurl from top down or inside out. Sometimes, new branches will form independently from the main tree, or multiple trees will form before a main tree even exists.
In these cases, Hat trees can be grafted onto other trees. This is done via a request-approve process where the wearer of one tree's topHat requests to link their topHat to a hat in another tree, whose admin can approve if desired. This has three main effects:
- The linked tophat loses its topHat status (i.e.,
Hats.isTopHat
will returnfalse
) and turns into what we call a "tree root" or "linked topHat", and - The hat to which it is linked becomes its new admin; it is no longer its own admin
- On linking, the linked topHat can be assigned eligibility and/or toggle modules like any other hat
Linked Hat trees can also be unlinked by the tree root from its linked admin, via Hats.unlinkTopHatFromTree
. This causes the tree root to regain its status as a top hat and to once again become its own admin. Any eligibility or toggle modules added on linking are cleared. Note that unlinking is only allowed if the tree root is active and has an eligible wearer.
⚠️ CAUTION: Be careful when nesting multiple Hat trees. If the nested linkages become too long, the higher level admins may lose control of the lowest level Hats because admin actions at that distance may cost-prohibitive or even exceed the gas limit. Best practice is to not attach external authorities (e.g. via token gating) to Hats in trees that are more than ~10 nested trees deep (varies by network).
Relinking
Linked topHats can be relinked to a different Hat within the same tree. This is useful for DAOs that want to reorganize their subtrees without having to go through the request and approve steps. Valid relinks must meet the following criteria in order to ensure security:
- The Hat wearer executing the relink is an admin of both the linked topHat and the new admin (destination)
- The new admin (destination) is within the same local tree as the existing admin (origin), or within the tippy top hat's local tree. Tippy top hats executing a relink are not subject to these restrictions.
- The new link does not create a circular linkage.
Renouncing a Hat
The wearer of a Hat can "take off" their Hat via Hats.renounceHat
. This burns the token and revokes any associated authorities and responsibilities from the now-former wearer, but does not put the wearer in bad standing.
Multicall
This contract inherits from Multicallable, which adds a non-payable multicall
function to the contract. This enables EOAs to make multiple calls to the contract atomically, unlocking a number of useful batch operations that were previously only available to smart contracts.
License
Distributed under the AGPLv3 License. See LICENSE.txt
for more information.
Contact
Spencer Graham - @spengrah
nintynick - @nintynick_
David Ehrlichman - @davehrlichman
Project Website: https://hatsprotocol.xyz/
Project Link: https://github.com/Hats-Protocol/hats-protocol/
Contents
HatsErrors
Errors
NotAdmin
Emitted when user
is attempting to perform an action on hatId
but is not wearing one of hatId
's admin hats
Can be equivalent to NotHatWearer(buildHatId(hatId))
, such as when emitted by approveLinkTopHatToTree
or relinkTopHatToTree
error NotAdmin(address user, uint256 hatId);
NotHatWearer
Emitted when attempting to perform an action as or for an account that is not a wearer of a given hat
error NotHatWearer();
NotAdminOrWearer
Emitted when attempting to perform an action that requires being either an admin or wearer of a given hat
error NotAdminOrWearer();
AllHatsWorn
Emitted when attempting to mint hatId
but hatId
's maxSupply has been reached
error AllHatsWorn(uint256 hatId);
MaxLevelsReached
Emitted when attempting to create a hat with a level 14 hat as its admin
error MaxLevelsReached();
InvalidHatId
Emitted when an attempted hat id has empty intermediate level(s)
error InvalidHatId();
AlreadyWearingHat
Emitted when attempting to mint hatId
to a wearer
who is already wearing the hat
error AlreadyWearingHat(address wearer, uint256 hatId);
HatDoesNotExist
Emitted when attempting to mint a non-existant hat
error HatDoesNotExist(uint256 hatId);
HatNotActive
Emmitted when attempting to mint or transfer a hat that is not active
error HatNotActive();
NotEligible
Emitted when attempting to mint or transfer a hat to an ineligible wearer
error NotEligible();
NotHatsToggle
Emitted when attempting to check or set a hat's status from an account that is not that hat's toggle module
error NotHatsToggle();
NotHatsEligibility
Emitted when attempting to check or set a hat wearer's status from an account that is not that hat's eligibility module
error NotHatsEligibility();
BatchArrayLengthMismatch
Emitted when array arguments to a batch function have mismatching lengths
error BatchArrayLengthMismatch();
Immutable
Emitted when attempting to mutate or transfer an immutable hat
error Immutable();
NewMaxSupplyTooLow
Emitted when attempting to change a hat's maxSupply to a value lower than its current supply
error NewMaxSupplyTooLow();
CircularLinkage
Emitted when attempting to link a tophat to a new admin for which the tophat serves as an admin
error CircularLinkage();
CrossTreeLinkage
Emitted when attempting to link or relink a tophat to a separate tree
error CrossTreeLinkage();
LinkageNotRequested
Emitted when attempting to link a tophat without a request
error LinkageNotRequested();
InvalidUnlink
Emitted when attempting to unlink a tophat that does not have a wearer
This ensures that unlinking never results in a bricked tophat
error InvalidUnlink();
ZeroAddress
Emmited when attempting to change a hat's eligibility or toggle module to the zero address
error ZeroAddress();
StringTooLong
Emmitted when attempting to change a hat's details or imageURI to a string with over 7000 bytes (~characters)
This protects against a DOS attack where an admin iteratively extend's a hat's details or imageURI
to be so long that reading it exceeds the block gas limit, breaking uri()
and viewHat()
error StringTooLong();
HatsEvents
Events
HatCreated
Emitted when a new hat is created
event HatCreated(
uint256 id, string details, uint32 maxSupply, address eligibility, address toggle, bool mutable_, string imageURI
);
Parameters
Name | Type | Description |
---|---|---|
id | uint256 | The id for the new hat |
details | string | A description of the Hat |
maxSupply | uint32 | The total instances of the Hat that can be worn at once |
eligibility | address | The address that can report on the Hat wearer's status |
toggle | address | The address that can deactivate the Hat |
mutable_ | bool | Whether the hat's properties are changeable after creation |
imageURI | string | The image uri for this hat and the fallback for its |
WearerStandingChanged
Emitted when a hat wearer's standing is updated
Eligibility is excluded since the source of truth for eligibility is the eligibility module and may change without a transaction
event WearerStandingChanged(uint256 hatId, address wearer, bool wearerStanding);
Parameters
Name | Type | Description |
---|---|---|
hatId | uint256 | The id of the wearer's hat |
wearer | address | The wearer's address |
wearerStanding | bool | Whether the wearer is in good standing for the hat |
HatStatusChanged
Emitted when a hat's status is updated
event HatStatusChanged(uint256 hatId, bool newStatus);
Parameters
Name | Type | Description |
---|---|---|
hatId | uint256 | The id of the hat |
newStatus | bool | Whether the hat is active |
HatDetailsChanged
Emitted when a hat's details are updated
event HatDetailsChanged(uint256 hatId, string newDetails);
Parameters
Name | Type | Description |
---|---|---|
hatId | uint256 | The id of the hat |
newDetails | string | The updated details |
HatEligibilityChanged
Emitted when a hat's eligibility module is updated
event HatEligibilityChanged(uint256 hatId, address newEligibility);
Parameters
Name | Type | Description |
---|---|---|
hatId | uint256 | The id of the hat |
newEligibility | address | The updated eligibiliy module |
HatToggleChanged
Emitted when a hat's toggle module is updated
event HatToggleChanged(uint256 hatId, address newToggle);
Parameters
Name | Type | Description |
---|---|---|
hatId | uint256 | The id of the hat |
newToggle | address | The updated toggle module |
HatMutabilityChanged
Emitted when a hat's mutability is updated
event HatMutabilityChanged(uint256 hatId);
Parameters
Name | Type | Description |
---|---|---|
hatId | uint256 | The id of the hat |
HatMaxSupplyChanged
Emitted when a hat's maximum supply is updated
event HatMaxSupplyChanged(uint256 hatId, uint32 newMaxSupply);
Parameters
Name | Type | Description |
---|---|---|
hatId | uint256 | The id of the hat |
newMaxSupply | uint32 | The updated max supply |
HatImageURIChanged
Emitted when a hat's image URI is updated
event HatImageURIChanged(uint256 hatId, string newImageURI);
Parameters
Name | Type | Description |
---|---|---|
hatId | uint256 | The id of the hat |
newImageURI | string | The updated image URI |
TopHatLinkRequested
Emitted when a tophat linkage is requested by its admin
event TopHatLinkRequested(uint32 domain, uint256 newAdmin);
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | The domain of the tree tophat to link |
newAdmin | uint256 | The tophat's would-be admin in the parent tree |
TopHatLinked
Emitted when a tophat is linked to a another tree
event TopHatLinked(uint32 domain, uint256 newAdmin);
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | The domain of the newly-linked tophat |
newAdmin | uint256 | The tophat's new admin in the parent tree |
IHats
Inherits: IHatsIdUtilities, HatsErrors, HatsEvents
Functions
mintTopHat
function mintTopHat(address _target, string memory _details, string memory _imageURI)
external
returns (uint256 topHatId);
createHat
function createHat(
uint256 _admin,
string calldata _details,
uint32 _maxSupply,
address _eligibility,
address _toggle,
bool _mutable,
string calldata _imageURI
) external returns (uint256 newHatId);
batchCreateHats
function batchCreateHats(
uint256[] calldata _admins,
string[] calldata _details,
uint32[] calldata _maxSupplies,
address[] memory _eligibilityModules,
address[] memory _toggleModules,
bool[] calldata _mutables,
string[] calldata _imageURIs
) external returns (bool success);
getNextId
function getNextId(uint256 _admin) external view returns (uint256 nextId);
mintHat
function mintHat(uint256 _hatId, address _wearer) external returns (bool success);
batchMintHats
function batchMintHats(uint256[] calldata _hatIds, address[] calldata _wearers) external returns (bool success);
setHatStatus
function setHatStatus(uint256 _hatId, bool _newStatus) external returns (bool toggled);
checkHatStatus
function checkHatStatus(uint256 _hatId) external returns (bool toggled);
setHatWearerStatus
function setHatWearerStatus(uint256 _hatId, address _wearer, bool _eligible, bool _standing)
external
returns (bool updated);
checkHatWearerStatus
function checkHatWearerStatus(uint256 _hatId, address _wearer) external returns (bool updated);
renounceHat
function renounceHat(uint256 _hatId) external;
transferHat
function transferHat(uint256 _hatId, address _from, address _to) external;
makeHatImmutable
function makeHatImmutable(uint256 _hatId) external;
changeHatDetails
function changeHatDetails(uint256 _hatId, string memory _newDetails) external;
changeHatEligibility
function changeHatEligibility(uint256 _hatId, address _newEligibility) external;
changeHatToggle
function changeHatToggle(uint256 _hatId, address _newToggle) external;
changeHatImageURI
function changeHatImageURI(uint256 _hatId, string memory _newImageURI) external;
changeHatMaxSupply
function changeHatMaxSupply(uint256 _hatId, uint32 _newMaxSupply) external;
requestLinkTopHatToTree
function requestLinkTopHatToTree(uint32 _topHatId, uint256 _newAdminHat) external;
approveLinkTopHatToTree
function approveLinkTopHatToTree(
uint32 _topHatId,
uint256 _newAdminHat,
address _eligibility,
address _toggle,
string calldata _details,
string calldata _imageURI
) external;
unlinkTopHatFromTree
function unlinkTopHatFromTree(uint32 _topHatId, address _wearer) external;
relinkTopHatWithinTree
function relinkTopHatWithinTree(
uint32 _topHatDomain,
uint256 _newAdminHat,
address _eligibility,
address _toggle,
string calldata _details,
string calldata _imageURI
) external;
viewHat
function viewHat(uint256 _hatId)
external
view
returns (
string memory details,
uint32 maxSupply,
uint32 supply,
address eligibility,
address toggle,
string memory imageURI,
uint16 lastHatId,
bool mutable_,
bool active
);
isWearerOfHat
function isWearerOfHat(address _user, uint256 _hatId) external view returns (bool isWearer);
isAdminOfHat
function isAdminOfHat(address _user, uint256 _hatId) external view returns (bool isAdmin);
isInGoodStanding
function isInGoodStanding(address _wearer, uint256 _hatId) external view returns (bool standing);
isEligible
function isEligible(address _wearer, uint256 _hatId) external view returns (bool eligible);
getHatEligibilityModule
function getHatEligibilityModule(uint256 _hatId) external view returns (address eligibility);
getHatToggleModule
function getHatToggleModule(uint256 _hatId) external view returns (address toggle);
getHatMaxSupply
function getHatMaxSupply(uint256 _hatId) external view returns (uint32 maxSupply);
hatSupply
function hatSupply(uint256 _hatId) external view returns (uint32 supply);
getImageURIForHat
function getImageURIForHat(uint256 _hatId) external view returns (string memory _uri);
balanceOf
function balanceOf(address wearer, uint256 hatId) external view returns (uint256 balance);
balanceOfBatch
function balanceOfBatch(address[] calldata _wearers, uint256[] calldata _hatIds)
external
view
returns (uint256[] memory);
uri
function uri(uint256 id) external view returns (string memory _uri);
IHatsEligibility
Functions
getWearerStatus
Returns the status of a wearer for a given hat
If standing is false, eligibility MUST also be false
function getWearerStatus(address _wearer, uint256 _hatId) external view returns (bool eligible, bool standing);
Parameters
Name | Type | Description |
---|---|---|
_wearer | address | The address of the current or prospective Hat wearer |
_hatId | uint256 | The id of the hat in question |
Returns
Name | Type | Description |
---|---|---|
eligible | bool | Whether the _wearer is eligible to wear the hat |
standing | bool | Whether the _wearer is in goog standing |
IHatsIdUtilities
Functions
buildHatId
function buildHatId(uint256 _admin, uint16 _newHat) external pure returns (uint256 id);
getHatLevel
function getHatLevel(uint256 _hatId) external view returns (uint32 level);
getLocalHatLevel
function getLocalHatLevel(uint256 _hatId) external pure returns (uint32 level);
isTopHat
function isTopHat(uint256 _hatId) external view returns (bool _topHat);
isLocalTopHat
function isLocalTopHat(uint256 _hatId) external pure returns (bool _localTopHat);
isValidHatId
function isValidHatId(uint256 _hatId) external view returns (bool validHatId);
getAdminAtLevel
function getAdminAtLevel(uint256 _hatId, uint32 _level) external view returns (uint256 admin);
getAdminAtLocalLevel
function getAdminAtLocalLevel(uint256 _hatId, uint32 _level) external pure returns (uint256 admin);
getTopHatDomain
function getTopHatDomain(uint256 _hatId) external view returns (uint32 domain);
getTippyTopHatDomain
function getTippyTopHatDomain(uint32 _topHatDomain) external view returns (uint32 domain);
noCircularLinkage
function noCircularLinkage(uint32 _topHatDomain, uint256 _linkedAdmin) external view returns (bool notCircular);
sameTippyTopHatDomain
function sameTippyTopHatDomain(uint32 _topHatDomain, uint256 _newAdminHat) external view returns (bool sameDomain);
IHatsToggle
Functions
getHatStatus
function getHatStatus(uint256 _hatId) external view returns (bool);
Hats
Inherits: IHats, ERC1155, Multicallable, HatsIdUtilities
Author: Haberdasher Labs
Hats are DAO-native, revocable, and programmable roles that are represented as non-transferable ERC-1155-similar tokens for composability
This is a multi-tenant contract that can manage all hats for a given chain. While it fully implements the ERC1155 interface, it does not fully comply with the ERC1155 standard.
State Variables
name
The name of the contract, typically including the version
string public name;
lastTopHatId
The first 4 bytes of the id of the last tophat created.
uint32 public lastTopHatId;
baseImageURI
The fallback image URI for hat tokens with no imageURI
specified in their branch
string public baseImageURI;
_hats
Internal mapping of hats to hat ids. See HatsIdUtilities.sol for more info on how hat ids work
mapping(uint256 => Hat) internal _hats;
badStandings
Mapping of wearers in bad standing for certain hats
Used by external contracts to trigger penalties for wearers in bad standing hatId => wearer => !standing
mapping(uint256 => mapping(address => bool)) public badStandings;
Functions
constructor
All arguments are immutable; they can only be set once during construction
constructor(string memory _name, string memory _baseImageURI);
Parameters
Name | Type | Description |
---|---|---|
_name | string | The name of this contract, typically including the version |
_baseImageURI | string | The fallback image URI |
mintTopHat
Creates and mints a Hat that is its own admin, i.e. a "topHat"
A topHat has no eligibility and no toggle
function mintTopHat(address _target, string calldata _details, string calldata _imageURI)
public
returns (uint256 topHatId);
Parameters
Name | Type | Description |
---|---|---|
_target | address | The address to which the newly created topHat is minted |
_details | string | A description of the Hat [optional]. Should not be larger than 7000 bytes (enforced in changeHatDetails) |
_imageURI | string | The image uri for this top hat and the fallback for its downstream hats [optional]. Should not be large than 7000 bytes (enforced in changeHatImageURI) |
Returns
Name | Type | Description |
---|---|---|
topHatId | uint256 | The id of the newly created topHat |
createHat
Creates a new hat. The msg.sender must wear the _admin
hat.
Initializes a new Hat struct, but does not mint any tokens.
function createHat(
uint256 _admin,
string calldata _details,
uint32 _maxSupply,
address _eligibility,
address _toggle,
bool _mutable,
string calldata _imageURI
) public returns (uint256 newHatId);
Parameters
Name | Type | Description |
---|---|---|
_admin | uint256 | The id of the Hat that will control who wears the newly created hat |
_details | string | A description of the Hat. Should not be larger than 7000 bytes (enforced in changeHatDetails) |
_maxSupply | uint32 | The total instances of the Hat that can be worn at once |
_eligibility | address | The address that can report on the Hat wearer's status |
_toggle | address | The address that can deactivate the Hat |
_mutable | bool | Whether the hat's properties are changeable after creation |
_imageURI | string | The image uri for this hat and the fallback for its downstream hats [optional]. Should not be larger than 7000 bytes (enforced in changeHatImageURI) |
Returns
Name | Type | Description |
---|---|---|
newHatId | uint256 | The id of the newly created Hat |
batchCreateHats
Creates new hats in batch. The msg.sender must be an admin of each hat.
This is a convenience function that loops through the arrays and calls createHat
.
function batchCreateHats(
uint256[] calldata _admins,
string[] calldata _details,
uint32[] calldata _maxSupplies,
address[] memory _eligibilityModules,
address[] memory _toggleModules,
bool[] calldata _mutables,
string[] calldata _imageURIs
) public returns (bool success);
Parameters
Name | Type | Description |
---|---|---|
_admins | uint256[] | Array of ids of admins for each hat to create |
_details | string[] | Array of details for each hat to create |
_maxSupplies | uint32[] | Array of supply caps for each hat to create |
_eligibilityModules | address[] | Array of eligibility module addresses for each hat to create |
_toggleModules | address[] | Array of toggle module addresses for each hat to create |
_mutables | bool[] | Array of mutable flags for each hat to create |
_imageURIs | string[] | Array of imageURIs for each hat to create |
Returns
Name | Type | Description |
---|---|---|
success | bool | True if all createHat calls succeeded |
getNextId
Gets the id of the next child hat of the hat _admin
Does not incrememnt lastHatId
function getNextId(uint256 _admin) public view returns (uint256 nextId);
Parameters
Name | Type | Description |
---|---|---|
_admin | uint256 | The id of the hat to serve as the admin for the next child hat |
Returns
Name | Type | Description |
---|---|---|
nextId | uint256 | The new hat id |
mintHat
Mints an ERC1155-similar token of the Hat to an eligible recipient, who then "wears" the hat
The msg.sender must wear an admin Hat of _hatId
, and the recipient must be eligible to wear _hatId
function mintHat(uint256 _hatId, address _wearer) public returns (bool success);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat to mint |
_wearer | address | The address to which the Hat is minted |
Returns
Name | Type | Description |
---|---|---|
success | bool | Whether the mint succeeded |
batchMintHats
Mints new hats in batch. The msg.sender must be an admin of each hat.
This is a convenience function that loops through the arrays and calls mintHat
.
function batchMintHats(uint256[] calldata _hatIds, address[] calldata _wearers) public returns (bool success);
Parameters
Name | Type | Description |
---|---|---|
_hatIds | uint256[] | Array of ids of hats to mint |
_wearers | address[] | Array of addresses to which the hats will be minted |
Returns
Name | Type | Description |
---|---|---|
success | bool | True if all mintHat calls succeeded |
setHatStatus
Toggles a Hat's status from active to deactive, or vice versa
The msg.sender must be set as the hat's toggle
function setHatStatus(uint256 _hatId, bool _newStatus) external returns (bool toggled);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat for which to adjust status |
_newStatus | bool | The new status to set |
Returns
Name | Type | Description |
---|---|---|
toggled | bool | Whether the status was toggled |
checkHatStatus
Checks a hat's toggle module and processes the returned status
May change the hat's status in storage
function checkHatStatus(uint256 _hatId) public returns (bool toggled);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat whose toggle we are checking |
Returns
Name | Type | Description |
---|---|---|
toggled | bool | Whether there was a new status |
_pullHatStatus
function _pullHatStatus(Hat storage _hat, uint256 _hatId) internal view returns (bool success, bool newStatus);
setHatWearerStatus
Report from a hat's eligibility on the status of one of its wearers and, if false
, revoke their hat
Burns the wearer's hat, if revoked
function setHatWearerStatus(uint256 _hatId, address _wearer, bool _eligible, bool _standing)
external
returns (bool updated);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the hat |
_wearer | address | The address of the hat wearer whose status is being reported |
_eligible | bool | Whether the wearer is eligible for the hat (will be revoked if false) |
_standing | bool | False if the wearer is no longer in good standing (and potentially should be penalized) |
Returns
Name | Type | Description |
---|---|---|
updated | bool | Whether the report succeeded |
checkHatWearerStatus
Check a hat's eligibility for a report on the status of one of the hat's wearers and, if false
, revoke their hat
Burns the wearer's hat, if revoked
function checkHatWearerStatus(uint256 _hatId, address _wearer) public returns (bool updated);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the hat |
_wearer | address | The address of the Hat wearer whose status report is being requested |
Returns
Name | Type | Description |
---|---|---|
updated | bool | Whether the wearer's status was altered |
renounceHat
Stop wearing a hat, aka "renounce" it
Burns the msg.sender's hat
function renounceHat(uint256 _hatId) external;
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat being renounced |
_createHat
Internal call for creating a new hat
Initializes a new Hat in storage, but does not mint any tokens
function _createHat(
uint256 _id,
string calldata _details,
uint32 _maxSupply,
address _eligibility,
address _toggle,
bool _mutable,
string calldata _imageURI
) internal;
Parameters
Name | Type | Description |
---|---|---|
_id | uint256 | ID of the hat to be stored |
_details | string | A description of the hat |
_maxSupply | uint32 | The total instances of the Hat that can be worn at once |
_eligibility | address | The address that can report on the Hat wearer's status |
_toggle | address | The address that can deactivate the hat [optional] |
_mutable | bool | Whether the hat's properties are changeable after creation |
_imageURI | string | The image uri for this top hat and the fallback for its downstream hats [optional] |
_processHatStatus
Internal function to process hat status
Updates a hat's status if different from current
function _processHatStatus(uint256 _hatId, bool _newStatus) internal returns (bool updated);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat in quest |
_newStatus | bool | The status to potentially change to |
Returns
Name | Type | Description |
---|---|---|
updated | bool | - Whether the status was updated |
_processHatWearerStatus
Internal call to process wearer status from the eligibility module
Burns the wearer's Hat token if _eligible is false, and updates badStandings state if necessary
function _processHatWearerStatus(uint256 _hatId, address _wearer, bool _eligible, bool _standing)
internal
returns (bool updated);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat to revoke |
_wearer | address | The address of the wearer in question |
_eligible | bool | Whether _wearer is eligible for the Hat (if false, this function will revoke their Hat) |
_standing | bool | Whether _wearer is in good standing (to be recorded in storage) |
Returns
Name | Type | Description |
---|---|---|
updated | bool | Whether the wearer standing was updated |
_setHatStatus
Internal function to set a hat's status in storage
Flips the 0th bit of _hat.config via bitwise operation
function _setHatStatus(Hat storage _hat, bool _status) internal;
Parameters
Name | Type | Description |
---|---|---|
_hat | Hat | The hat object |
_status | bool | The status to set for the hat |
_staticBalanceOf
Internal function to retrieve an account's internal "static" balance directly from internal storage,
This function bypasses the dynamic _isActive
and _isEligible
checks
function _staticBalanceOf(address _account, uint256 _hatId) internal view returns (uint256 staticBalance);
Parameters
Name | Type | Description |
---|---|---|
_account | address | The account to check |
_hatId | uint256 | The hat to check |
Returns
Name | Type | Description |
---|---|---|
staticBalance | uint256 | The account's static of the hat, from internal storage |
_checkAdmin
Checks whether msg.sender is an admin of a hat, and reverts if not
function _checkAdmin(uint256 _hatId) internal view;
_checkAdminOrWearer
checks whether the msg.sender is either an admin or wearer or a hat, and reverts the appropriate error if not
function _checkAdminOrWearer(uint256 _hatId) internal view;
transferHat
Transfers a hat from one wearer to another eligible wearer
The hat must be mutable, and the transfer must be initiated by an admin
function transferHat(uint256 _hatId, address _from, address _to) public;
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The hat in question |
_from | address | The current wearer |
_to | address | The new wearer |
makeHatImmutable
Set a mutable hat to immutable
Sets the second bit of hat.config to 0
function makeHatImmutable(uint256 _hatId) external;
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat to make immutable |
changeHatDetails
Change a hat's details
Hat must be mutable, except for tophats.
function changeHatDetails(uint256 _hatId, string calldata _newDetails) external;
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat to change |
_newDetails | string | The new details. Must not be larger than 7000 bytes. |
changeHatEligibility
Change a hat's details
Hat must be mutable
function changeHatEligibility(uint256 _hatId, address _newEligibility) external;
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat to change |
_newEligibility | address | The new eligibility module |
changeHatToggle
Change a hat's details
Hat must be mutable
function changeHatToggle(uint256 _hatId, address _newToggle) external;
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat to change |
_newToggle | address | The new toggle module |
changeHatImageURI
Change a hat's details
Hat must be mutable, except for tophats
function changeHatImageURI(uint256 _hatId, string calldata _newImageURI) external;
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat to change |
_newImageURI | string | The new imageURI. Must not be larger than 7000 bytes. |
changeHatMaxSupply
Change a hat's details
Hat must be mutable; new max supply cannot be less than current supply
function changeHatMaxSupply(uint256 _hatId, uint32 _newMaxSupply) external;
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat to change |
_newMaxSupply | uint32 | The new max supply |
requestLinkTopHatToTree
Submits a request to link a Hat Tree under a parent tree. Requests can be submitted by either... a) the wearer of a topHat, previous to any linkage, or b) the admin(s) of an already-linked topHat (aka tree root), where such a request is to move the tree root to another admin within the same parent tree
A topHat can have at most 1 request at a time. Submitting a new request will replace the existing request.
function requestLinkTopHatToTree(uint32 _topHatDomain, uint256 _requestedAdminHat) external;
Parameters
Name | Type | Description |
---|---|---|
_topHatDomain | uint32 | The domain of the topHat to link |
_requestedAdminHat | uint256 | The hat that will administer the linked tree |
approveLinkTopHatToTree
Approve a request to link a Tree under a parent tree, with options to add eligibility or toggle modules and change its metadata
Requests can only be approved by wearer or an admin of the _newAdminHat
, and there
can only be one link per tree root at a given time.
function approveLinkTopHatToTree(
uint32 _topHatDomain,
uint256 _newAdminHat,
address _eligibility,
address _toggle,
string calldata _details,
string calldata _imageURI
) external;
Parameters
Name | Type | Description |
---|---|---|
_topHatDomain | uint32 | The 32 bit domain of the topHat to link |
_newAdminHat | uint256 | The hat that will administer the linked tree |
_eligibility | address | Optional new eligibility module for the linked topHat |
_toggle | address | Optional new toggle module for the linked topHat |
_details | string | Optional new details for the linked topHat |
_imageURI | string | Optional new imageURI for the linked topHat |
unlinkTopHatFromTree
Unlink a Tree from the parent tree
*This can only be called by an admin of the tree root. Fails if the topHat to unlink has no non-zero wearer, which can occur if...
- It's wearer is in badStanding
- It has been revoked from its wearer (and possibly burned)˘
- It is not active (ie toggled off)*
function unlinkTopHatFromTree(uint32 _topHatDomain, address _wearer) external;
Parameters
Name | Type | Description |
---|---|---|
_topHatDomain | uint32 | The 32 bit domain of the topHat to unlink |
_wearer | address | The current wearer of the topHat to unlink |
relinkTopHatWithinTree
Move a tree root to a different position within the same parent tree, without a request. Valid destinations include within the same local tree as the origin, or to the local tree of the tippyTopHat. TippyTopHat wearers can bypass this restriction to relink to anywhere in its full tree.
Caller must be both an admin tree root and admin or wearer of _newAdminHat
.
function relinkTopHatWithinTree(
uint32 _topHatDomain,
uint256 _newAdminHat,
address _eligibility,
address _toggle,
string calldata _details,
string calldata _imageURI
) external;
Parameters
Name | Type | Description |
---|---|---|
_topHatDomain | uint32 | The 32 bit domain of the topHat to relink |
_newAdminHat | uint256 | The new admin for the linked tree |
_eligibility | address | Optional new eligibility module for the linked topHat |
_toggle | address | Optional new toggle module for the linked topHat |
_details | string | Optional new details for the linked topHat |
_imageURI | string | Optional new imageURI for the linked topHat |
_linkTopHatToTree
Internal function to link a Tree under a parent Tree, with protection against circular linkages and relinking to a separate Tree, with options to add eligibility or toggle modules and change its metadata
Linking _topHatDomain
replaces any existing links
function _linkTopHatToTree(
uint32 _topHatDomain,
uint256 _newAdminHat,
address _eligibility,
address _toggle,
string calldata _details,
string calldata _imageURI
) internal;
Parameters
Name | Type | Description |
---|---|---|
_topHatDomain | uint32 | The 32 bit domain of the topHat to link |
_newAdminHat | uint256 | The new admin for the linked tree |
_eligibility | address | Optional new eligibility module for the linked topHat |
_toggle | address | Optional new toggle module for the linked topHat |
_details | string | Optional new details for the linked topHat |
_imageURI | string | Optional new imageURI for the linked topHat |
viewHat
View the properties of a given Hat
function viewHat(uint256 _hatId)
public
view
returns (
string memory details,
uint32 maxSupply,
uint32 supply,
address eligibility,
address toggle,
string memory imageURI,
uint16 lastHatId,
bool mutable_,
bool active
);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat |
Returns
Name | Type | Description |
---|---|---|
details | string | The details of the Hat |
maxSupply | uint32 | The max supply of tokens for this Hat |
supply | uint32 | The number of current wearers of this Hat |
eligibility | address | The eligibility address for this Hat |
toggle | address | The toggle address for this Hat |
imageURI | string | The image URI used for this Hat |
lastHatId | uint16 | The most recently created Hat with this Hat as admin; also the count of Hats with this Hat as admin |
mutable_ | bool | Whether this hat's properties can be changed |
active | bool | Whether the Hat is current active, as read from _isActive |
isWearerOfHat
Checks whether a given address wears a given Hat
Convenience function that wraps balanceOf
function isWearerOfHat(address _user, uint256 _hatId) public view returns (bool isWearer);
Parameters
Name | Type | Description |
---|---|---|
_user | address | The address in question |
_hatId | uint256 | The id of the Hat that the _user might wear |
Returns
Name | Type | Description |
---|---|---|
isWearer | bool | Whether the _user wears the Hat. |
isAdminOfHat
Checks whether a given address serves as the admin of a given Hat
Recursively checks if _user
wears the admin Hat of the Hat in question. This is recursive since there may be a string of Hats as admins of Hats.
function isAdminOfHat(address _user, uint256 _hatId) public view returns (bool isAdmin);
Parameters
Name | Type | Description |
---|---|---|
_user | address | The address in question |
_hatId | uint256 | The id of the Hat for which the _user might be the admin |
Returns
Name | Type | Description |
---|---|---|
isAdmin | bool | Whether the _user has admin rights for the Hat |
_isActive
Checks the active status of a hat
For internal use instead of isActive
when passing Hat as param is preferable
function _isActive(Hat storage _hat, uint256 _hatId) internal view returns (bool active);
Parameters
Name | Type | Description |
---|---|---|
_hat | Hat | The Hat struct |
_hatId | uint256 | The id of the hat |
Returns
Name | Type | Description |
---|---|---|
active | bool | The active status of the hat |
isActive
Checks the active status of a hat
function isActive(uint256 _hatId) external view returns (bool active);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the hat |
Returns
Name | Type | Description |
---|---|---|
active | bool | Whether the hat is active |
_getHatStatus
Internal function to retrieve a hat's status from storage
reads the 0th bit of the hat's config
function _getHatStatus(Hat storage _hat) internal view returns (bool status);
Parameters
Name | Type | Description |
---|---|---|
_hat | Hat | The hat object |
Returns
Name | Type | Description |
---|---|---|
status | bool | Whether the hat is active |
_isMutable
Internal function to retrieve a hat's mutability setting
reads the 1st bit of the hat's config
function _isMutable(Hat storage _hat) internal view returns (bool _mutable);
Parameters
Name | Type | Description |
---|---|---|
_hat | Hat | The hat object |
Returns
Name | Type | Description |
---|---|---|
_mutable | bool | Whether the hat is mutable |
isInGoodStanding
Checks whether a wearer of a Hat is in good standing
function isInGoodStanding(address _wearer, uint256 _hatId) public view returns (bool standing);
Parameters
Name | Type | Description |
---|---|---|
_wearer | address | The address of the Hat wearer |
_hatId | uint256 | The id of the Hat |
Returns
Name | Type | Description |
---|---|---|
standing | bool | Whether the wearer is in good standing |
_isEligible
Internal call to check whether an address is eligible for a given Hat
Tries an external call to the Hat's eligibility module, defaulting to existing badStandings state if the call fails (ie if the eligibility module address does not conform to the IHatsEligibility interface)
function _isEligible(address _wearer, Hat storage _hat, uint256 _hatId) internal view returns (bool eligible);
Parameters
Name | Type | Description |
---|---|---|
_wearer | address | The address of the Hat wearer |
_hat | Hat | The Hat object |
_hatId | uint256 | The id of the Hat |
Returns
Name | Type | Description |
---|---|---|
eligible | bool | Whether the wearer is eligible for the Hat |
isEligible
Checks whether an address is eligible for a given Hat
Public function for use when passing a Hat object is not possible or preferable
function isEligible(address _wearer, uint256 _hatId) public view returns (bool eligible);
Parameters
Name | Type | Description |
---|---|---|
_wearer | address | The address to check |
_hatId | uint256 | The id of the Hat |
Returns
Name | Type | Description |
---|---|---|
eligible | bool | Whether the wearer is eligible for the Hat |
hatSupply
Gets the current supply of a Hat
Only tracks explicit burns and mints, not dynamic revocations
function hatSupply(uint256 _hatId) external view returns (uint32 supply);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat |
Returns
Name | Type | Description |
---|---|---|
supply | uint32 | The current supply of the Hat |
getHatEligibilityModule
Gets the eligibility module for a hat
function getHatEligibilityModule(uint256 _hatId) external view returns (address eligibility);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The hat whose eligibility module we're looking for |
Returns
Name | Type | Description |
---|---|---|
eligibility | address | The eligibility module for this hat |
getHatToggleModule
Gets the toggle module for a hat
function getHatToggleModule(uint256 _hatId) external view returns (address toggle);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The hat whose toggle module we're looking for |
Returns
Name | Type | Description |
---|---|---|
toggle | address | The toggle module for this hat |
getHatMaxSupply
Gets the max supply for a hat
function getHatMaxSupply(uint256 _hatId) external view returns (uint32 maxSupply);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The hat whose max supply we're looking for |
Returns
Name | Type | Description |
---|---|---|
maxSupply | uint32 | The maximum possible quantity of this hat that could be minted |
getImageURIForHat
Gets the imageURI for a given hat
If this hat does not have an imageURI set, recursively get the imageURI from its admin
function getImageURIForHat(uint256 _hatId) public view returns (string memory _uri);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The hat whose imageURI we're looking for |
Returns
Name | Type | Description |
---|---|---|
_uri | string | The imageURI of this hat or, if empty, its admin |
_constructURI
Constructs the URI for a Hat, using data from the Hat struct
function _constructURI(uint256 _hatId) internal view returns (string memory _uri);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The id of the Hat |
Returns
Name | Type | Description |
---|---|---|
_uri | string | An ERC1155-compatible JSON string |
balanceOf
Gets the Hat token balance of a user for a given Hat
Balance is dynamic based on the hat's status and wearer's eligibility, so off-chain balance data indexed from events may not be in sync
function balanceOf(address _wearer, uint256 _hatId) public view override(ERC1155, IHats) returns (uint256 balance);
Parameters
Name | Type | Description |
---|---|---|
_wearer | address | The address whose balance is being checked |
_hatId | uint256 | The id of the Hat |
Returns
Name | Type | Description |
---|---|---|
balance | uint256 | The wearer 's balance of the Hat tokens. Can never be > 1. |
_mintHat
Internal call to mint a Hat token to a wearer
Unsafe if called when _wearer
has a non-zero balance of _hatId
function _mintHat(address _wearer, uint256 _hatId) internal;
Parameters
Name | Type | Description |
---|---|---|
_wearer | address | The wearer of the Hat and the recipient of the newly minted token |
_hatId | uint256 | The id of the Hat to mint |
_burnHat
Internal call to burn a wearer's Hat token
Unsafe if called when _wearer
doesn't have a zero balance of _hatId
function _burnHat(address _wearer, uint256 _hatId) internal;
Parameters
Name | Type | Description |
---|---|---|
_wearer | address | The wearer from which to burn the Hat token |
_hatId | uint256 | The id of the Hat to burn |
setApprovalForAll
Approvals are not necessary for Hats since transfers are not handled by the wearer
Admins should use transferHat()
to transfer
function setApprovalForAll(address, bool) public pure override;
safeTransferFrom
Safe transfers are not necessary for Hats since transfers are not handled by the wearer
Admins should use transferHat()
to transfer
function safeTransferFrom(address, address, uint256, uint256, bytes calldata) public pure override;
safeBatchTransferFrom
Safe transfers are not necessary for Hats since transfers are not handled by the wearer
function safeBatchTransferFrom(address, address, uint256[] calldata, uint256[] calldata, bytes calldata)
public
pure
override;
supportsInterface
ERC165 interface detection
While Hats Protocol conforms to the ERC1155 interface, it does not fully conform to the ERC1155 specification since it does not implement the ERC1155Receiver functionality. For this reason, this function overrides the ERC1155 implementation to return false for ERC1155.
function supportsInterface(bytes4 interfaceId) public pure override returns (bool);
Parameters
Name | Type | Description |
---|---|---|
interfaceId | bytes4 | The interface identifier, as specified in ERC-165 |
Returns
Name | Type | Description |
---|---|---|
<none> | bool | bool True if the contract implements interfaceId and false otherwise |
balanceOfBatch
Batch retrieval for wearer balances
Given the higher gas overhead of Hats balanceOf checks, large batches may be high cost or run into gas limits
function balanceOfBatch(address[] calldata _wearers, uint256[] calldata _hatIds)
public
view
override(ERC1155, IHats)
returns (uint256[] memory balances);
Parameters
Name | Type | Description |
---|---|---|
_wearers | address[] | Array of addresses to check balances for |
_hatIds | uint256[] | Array of Hat ids to check, using the same index as _wearers |
uri
View the uri for a Hat
function uri(uint256 id) public view override(ERC1155, IHats) returns (string memory _uri);
Parameters
Name | Type | Description |
---|---|---|
id | uint256 | The id of the Hat |
Returns
Name | Type | Description |
---|---|---|
_uri | string | An 1155-compatible JSON object |
Structs
Hat
This contract's version is labeled v1. Previous versions labeled similarly as v1 and v1.0 are deprecated, and should be treated as beta deployments.
A Hat object containing the hat's properties
The members are packed to minimize storage costs
struct Hat {
address eligibility;
uint32 maxSupply;
uint32 supply;
uint16 lastHatId;
address toggle;
uint96 config;
string details;
string imageURI;
}
MaxLevelsReached
see HatsErrors.sol for description
error MaxLevelsReached();
HatsIdUtilities
Inherits: IHatsIdUtilities
Author: Haberdasher Labs
Functions for working with Hat Ids from Hats Protocol. Factored out of Hats.sol for easier use by other contracts.
State Variables
linkedTreeRequests
Mapping of tophats requesting to link to admin hats in other trees
Linkage only occurs if request is approved by the new admin
mapping(uint32 => uint256) public linkedTreeRequests;
linkedTreeAdmins
Mapping of approved & linked tophats to admin hats in other trees, used for grafting one hats tree onto another
Trees can only be linked to another tree via their tophat
mapping(uint32 => uint256) public linkedTreeAdmins;
TOPHAT_ADDRESS_SPACE
Hat Ids serve as addresses. A given Hat's Id represents its location in its hat tree: its level, its admin, its admin's admin (etc, all the way up to the tophat). The top level consists of 4 bytes and references all tophats. Each level below consists of 16 bits, and contains up to 65,536 child hats. A uint256 contains 4 bytes of space for tophat addresses, giving room for ((256 - 32) / 16) = 14 levels of delegation, with the admin at each level having space for 65,536 different child hats. A hat tree consists of a single tophat and has a max depth of 14 levels.
Number of bits of address space for tophat ids, ie the tophat domain
uint256 internal constant TOPHAT_ADDRESS_SPACE = 32;
LOWER_LEVEL_ADDRESS_SPACE
Number of bits of address space for each level below the tophat
uint256 internal constant LOWER_LEVEL_ADDRESS_SPACE = 16;
MAX_LEVELS
Maximum number of levels below the tophat, ie max tree depth (256 - TOPHAT_ADDRESS_SPACE) / LOWER_LEVEL_ADDRESS_SPACE;
uint256 internal constant MAX_LEVELS = 14;
Functions
buildHatId
Constructs a valid hat id for a new hat underneath a given admin
Reverts if the admin has already reached MAX_LEVELS
function buildHatId(uint256 _admin, uint16 _newHat) public pure returns (uint256 id);
Parameters
Name | Type | Description |
---|---|---|
_admin | uint256 | the id of the admin for the new hat |
_newHat | uint16 | the uint16 id of the new hat |
Returns
Name | Type | Description |
---|---|---|
id | uint256 | The constructed hat id |
getHatLevel
Identifies the level a given hat in its hat tree
function getHatLevel(uint256 _hatId) public view returns (uint32 level);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | the id of the hat in question |
Returns
Name | Type | Description |
---|---|---|
level | uint32 | (0 to type(uint32).max) |
getLocalHatLevel
Identifies the level a given hat in its local hat tree
Similar to getHatLevel, but does not account for linked trees
function getLocalHatLevel(uint256 _hatId) public pure returns (uint32 level);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | the id of the hat in question |
Returns
Name | Type | Description |
---|---|---|
level | uint32 | The local level, from 0 to 14 |
isTopHat
Checks whether a hat is a topHat
function isTopHat(uint256 _hatId) public view returns (bool _isTopHat);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The hat in question |
Returns
Name | Type | Description |
---|---|---|
_isTopHat | bool | Whether the hat is a topHat |
isLocalTopHat
Checks whether a hat is a topHat in its local hat tree
Similar to isTopHat, but does not account for linked trees
function isLocalTopHat(uint256 _hatId) public pure returns (bool _isLocalTopHat);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | The hat in question |
Returns
Name | Type | Description |
---|---|---|
_isLocalTopHat | bool | Whether the hat is a topHat for its local tree |
isValidHatId
function isValidHatId(uint256 _hatId) public pure returns (bool validHatId);
getAdminAtLevel
Gets the hat id of the admin at a given level of a given hat
This function traverses trees by following the linkedTreeAdmin pointer to a hat located in a different tree
function getAdminAtLevel(uint256 _hatId, uint32 _level) public view returns (uint256 admin);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | the id of the hat in question |
_level | uint32 | the admin level of interest |
Returns
Name | Type | Description |
---|---|---|
admin | uint256 | The hat id of the resulting admin |
getAdminAtLocalLevel
Gets the hat id of the admin at a given level of a given hat local to the tree containing the hat.
function getAdminAtLocalLevel(uint256 _hatId, uint32 _level) public pure returns (uint256 admin);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | the id of the hat in question |
_level | uint32 | the admin level of interest |
Returns
Name | Type | Description |
---|---|---|
admin | uint256 | The hat id of the resulting admin |
getTopHatDomain
Gets the tophat domain of a given hat
A domain is the identifier for a given hat tree, stored in the first 4 bytes of a hat's id
function getTopHatDomain(uint256 _hatId) public pure returns (uint32 domain);
Parameters
Name | Type | Description |
---|---|---|
_hatId | uint256 | the id of the hat in question |
Returns
Name | Type | Description |
---|---|---|
domain | uint32 | The domain of the hat's tophat |
getTippyTopHatDomain
Gets the domain of the highest parent tophat — the "tippy tophat"
function getTippyTopHatDomain(uint32 _topHatDomain) public view returns (uint32 domain);
Parameters
Name | Type | Description |
---|---|---|
_topHatDomain | uint32 | the 32 bit domain of a (likely linked) tophat |
Returns
Name | Type | Description |
---|---|---|
domain | uint32 | The tippy tophat domain |
noCircularLinkage
Checks For any circular linkage of trees
function noCircularLinkage(uint32 _topHatDomain, uint256 _linkedAdmin) public view returns (bool notCircular);
Parameters
Name | Type | Description |
---|---|---|
_topHatDomain | uint32 | the 32 bit domain of the tree to be linked |
_linkedAdmin | uint256 | the hatId of the potential tree admin |
Returns
Name | Type | Description |
---|---|---|
notCircular | bool | circular link has not been found |
sameTippyTopHatDomain
Checks that a tophat domain and its potential linked admin are from the same tree, ie have the same tippy tophat domain
function sameTippyTopHatDomain(uint32 _topHatDomain, uint256 _newAdminHat) public view returns (bool sameDomain);
Parameters
Name | Type | Description |
---|---|---|
_topHatDomain | uint32 | The 32 bit domain of the tophat to be linked |
_newAdminHat | uint256 | The new admin for the linked tree |
Returns
Name | Type | Description |
---|---|---|
sameDomain | bool | Whether the _topHatDomain and the domain of its potential linked _newAdminHat domains are the same |