Unbound recursive function call can use unlimited gas and break hats operation
some of the functions in the Hats and HatsIdUtilities contracts has recursive logics without limiting the number of iteration, this can cause unlimited gas usage if hat trees has huge depth and it won't be possible to call the contracts functions. functions `getImageURIForHat()`, `isAdminOfHat()`, `getTippyTopHatDomain()` and `noCircularLinkage()` would revert and because most of the logics callings those functions so contract would be in broken state for those hats.\\nThis is function `isAdminOfHat()` code:\\n```\\n    function isAdminOfHat(address _user, uint256 _hatId) public view returns (bool isAdmin) {\\n        uint256 linkedTreeAdmin;\\n        uint32 adminLocalHatLevel;\\n        if (isLocalTopHat(_hatId)) {\\n            linkedTreeAdmin = linkedTreeAdmins[getTopHatDomain(_hatId)];\\n            if (linkedTreeAdmin == 0) {\\n                // tree is not linked\\n                return isAdmin = isWearerOfHat(_user, _hatId);\\n            } else {\\n                // tree is linked\\n                if (isWearerOfHat(_user, linkedTreeAdmin)) {\\n                    return isAdmin = true;\\n                } // user wears the treeAdmin\\n                else {\\n                    adminLocalHatLevel = getLocalHatLevel(linkedTreeAdmin);\\n                    _hatId = linkedTreeAdmin;\\n                }\\n            }\\n        } else {\\n            // if we get here, _hatId is not a tophat of any kind\\n            // get the local tree level of _hatId's admin\\n            adminLocalHatLevel = getLocalHatLevel(_hatId) - 1;\\n        }\\n\\n        // search up _hatId's local address space for an admin hat that the _user wears\\n        while (adminLocalHatLevel > 0) {\\n            if (isWearerOfHat(_user, getAdminAtLocalLevel(_hatId, adminLocalHatLevel))) {\\n                return isAdmin = true;\\n            }\\n            // should not underflow given stopping condition > 0\\n            unchecked {\\n                --adminLocalHatLevel;\\n            }\\n        }\\n\\n        // if we get here, we've reached the top of _hatId's local tree, ie the local tophat\\n        // check if the user wears the local tophat\\n        if (isWearerOfHat(_user, getAdminAtLocalLevel(_hatId, 0))) return isAdmin = true;\\n\\n        // if not, we check if it's linked to another tree\\n        linkedTreeAdmin = linkedTreeAdmins[getTopHatDomain(_hatId)];\\n        if (linkedTreeAdmin == 0) {\\n            // tree is not linked\\n            // we've already learned that user doesn't wear the local tophat, so there's nothing else to check; we return false\\n            return isAdmin = false;\\n        } else {\\n            // tree is linked\\n            // check if user is wearer of linkedTreeAdmin\\n            if (isWearerOfHat(_user, linkedTreeAdmin)) return true;\\n            // if not, recurse to traverse the parent tree for a hat that the user wears\\n            isAdmin = isAdminOfHat(_user, linkedTreeAdmin);\\n        }\\n    }\\n```\\n\\nAs you can see this function calls itself recursively to check that if user is wearer of the one of the upper link hats of the hat or not. if the chain(depth) of the hats in the tree become very long then this function would revert because of the gas usage and the gas usage would be high enough so it won't be possible to call this function in a transaction. functions `getImageURIForHat()`, `getTippyTopHatDomain()` and `noCircularLinkage()` has similar issues and the gas usage is depend on the tree depth. the issue can happen suddenly for hats if the top level topHat decide to add link, for example:\\nHat1 is linked to chain of the hats that has 1000 "root hat" and the topHat (tippy hat) is TIPHat1.\\nHat2 is linked to chain of the hats that has 1000 "root hat" and the topHat (tippy hat) is TIPHat2.\\nadmin of the TIPHat1 decides to link it to the Hat2 and all and after performing that the total depth of the tree would increase to 2000 and transactions would cost double time gas.
code should check and make sure that hat levels has a maximum level and doesn't allow actions when this level breaches. (keep depth of each tophat's tree and update it when actions happens and won't allow actions if they increase depth higher than the threshold)
it won't be possible to perform actions for those hats and funds can be lost because of it.
```\\n    function isAdminOfHat(address _user, uint256 _hatId) public view returns (bool isAdmin) {\\n        uint256 linkedTreeAdmin;\\n        uint32 adminLocalHatLevel;\\n        if (isLocalTopHat(_hatId)) {\\n            linkedTreeAdmin = linkedTreeAdmins[getTopHatDomain(_hatId)];\\n            if (linkedTreeAdmin == 0) {\\n                // tree is not linked\\n                return isAdmin = isWearerOfHat(_user, _hatId);\\n            } else {\\n                // tree is linked\\n                if (isWearerOfHat(_user, linkedTreeAdmin)) {\\n                    return isAdmin = true;\\n                } // user wears the treeAdmin\\n                else {\\n                    adminLocalHatLevel = getLocalHatLevel(linkedTreeAdmin);\\n                    _hatId = linkedTreeAdmin;\\n                }\\n            }\\n        } else {\\n            // if we get here, _hatId is not a tophat of any kind\\n            // get the local tree level of _hatId's admin\\n            adminLocalHatLevel = getLocalHatLevel(_hatId) - 1;\\n        }\\n\\n        // search up _hatId's local address space for an admin hat that the _user wears\\n        while (adminLocalHatLevel > 0) {\\n            if (isWearerOfHat(_user, getAdminAtLocalLevel(_hatId, adminLocalHatLevel))) {\\n                return isAdmin = true;\\n            }\\n            // should not underflow given stopping condition > 0\\n            unchecked {\\n                --adminLocalHatLevel;\\n            }\\n        }\\n\\n        // if we get here, we've reached the top of _hatId's local tree, ie the local tophat\\n        // check if the user wears the local tophat\\n        if (isWearerOfHat(_user, getAdminAtLocalLevel(_hatId, 0))) return isAdmin = true;\\n\\n        // if not, we check if it's linked to another tree\\n        linkedTreeAdmin = linkedTreeAdmins[getTopHatDomain(_hatId)];\\n        if (linkedTreeAdmin == 0) {\\n            // tree is not linked\\n            // we've already learned that user doesn't wear the local tophat, so there's nothing else to check; we return false\\n            return isAdmin = false;\\n        } else {\\n            // tree is linked\\n            // check if user is wearer of linkedTreeAdmin\\n            if (isWearerOfHat(_user, linkedTreeAdmin)) return true;\\n            // if not, recurse to traverse the parent tree for a hat that the user wears\\n            isAdmin = isAdminOfHat(_user, linkedTreeAdmin);\\n        }\\n    }\\n```\\n