Request and approval flow for tophat links#85
Conversation
src/Hats.sol
Outdated
| /// @notice Internal function to link a Tree under a parent Tree | ||
| /// @dev Linking `_topHatId` replaces any existing links | ||
| /// @param _topHatId The domain of the tophat to link | ||
| /// @param _newAdminHat The new admin for the linked tree |
There was a problem hiding this comment.
Pretty sure natspec docstings aren't extracted from non-external/public functions, but I still think these are good practice.
src/Hats.sol
Outdated
| // Linkages must be initiated by a request | ||
| if (_newAdminHat != linkedTreeRequests[_topHatId]) revert LinkageNotRequested(); |
There was a problem hiding this comment.
might we want to potentially bypass this if the msg.sender also wears the tophat of the candidate child tree?
There was a problem hiding this comment.
@topocount Defined a separate function relinkTopHatWithinTree for that purpose. I could see the benefit of both clearer separation of concerns (ie w/ separate functions) and also of smaller code size (single function).
gershido
left a comment
There was a problem hiding this comment.
Hi all! @topocount I didn't have the chance to say hi on another platform so better GitHub than nothing :)
src/Hats.sol
Outdated
| function relinkTopHatWithinTree(uint32 _topHatId, uint256 _newAdminHat) external { | ||
| uint256 fullTopHatId = uint256(_topHatId) << 224; // (256 - TOPHAT_ADDRESS_SPACE); | ||
|
|
||
| // msg.sender being capable of both requesting and approving allows us to skip the request step | ||
| _checkAdmin(fullTopHatId); // "requester" | ||
| _checkAdmin(_newAdminHat); // "approver" | ||
|
|
||
| // execute the new link, replacing the old link | ||
| _linkTopHatToTree(_topHatId, _newAdminHat); | ||
| } |
There was a problem hiding this comment.
Two things that the function can currently do which may be a problem:
- Link
_topHatIdfor the first time without passing thenoCircularLinkagetest, in case the owner of_topHatIdis also an admin of_newAdminHat. - Link
_topHatIdto a completely different tree than it is currently linked.
I guess the ideal is to check that _topHatId is currently linked to the tree that includes _newAdminHat by checking that they have a common ancestor (which is not _topHatId). But if implementing that is too expensive in terms of code size, maybe only preventing 1 by including a check that linkedTreeAdmins[_topHatId] != 0 and the noCircularLinkage test is good enough.
There was a problem hiding this comment.
Good points.
For (1) noCircularLinkage should always be checked whenever a new link is being created, so I think the best bet is to include it in _linkTopHatToTree. Will push up that change.
For (2), I'm actually not sure we want to prevent this. If a DAO has a few different linked trees under its main tophat, I think it makes sense for the DAO to be able to move one of those linked trees to underneath another (provided it doesn't create a circular linkage, of course). Similarly, if a DAO was wearing two tophats, it makes sense for the DAO to be able to link one of those tophats under the other, or move a third linked tree from one to the other.
Do you see a downside to that, @gershido? Also interested in @topocount @nintynick @davehrlichman thoughts here.
There was a problem hiding this comment.
I agree with Spencer here, that “it makes sense for the DAO to be able to move one of those linked trees to underneath another (provided it doesn't create a circular linkage, of course). Similarly, if a DAO was wearing two tophats, it makes sense for the DAO to be able to link one of those tophats under the other, or move a third linked tree from one to the other.”
There was a problem hiding this comment.
In (2), I meant the possibility to relink a subtree to a tree that is not the parent tree and also not a tree that is linked to the parent tree. The thing that worries me is that if an admin hat becomes a bad actor, it can just "steal" a subtree to a dummy tree that it created and this would be non recoverable by the rest of the admins in the original tree. But on the other hand, the use case of a DAO with two top hats seems also useful...
I think the question of resiliency against possible actions will be very important once there are significant resources that are attached to hats
There was a problem hiding this comment.
Ah, I see what you mean. So if we allow DAOs to move subtrees among their multiple tophats, we leave open an attack vector where a corrupted hat could steal a subtree.
I think I'm with you that the risk of the latter is larger than the benefit of the former, at least currently. We've been thinking about future registry feature that allows a DAO to "register" multiple tophats, creating a non-hierarchical association between trees; we could then allow moving subtrees across parent trees as long as all parent trees are registered to the same DAO.
But until then, I think it does make sense to constrain relinking to with-in tree moves if we can make the check feasible computationally and wrt bytecode size limits. I'll see what I can whip up today.
|
@slgraham and I just paired to review this PR. Overall it looks good in the current state, pending some small changes coming shortly. Documenting some of the considerations we discussed:
Strong work!! 🧢 |
The bulk of these changes are:
|
|
All looks good to me except one edge case regarding point (1): |
Great catch @gershido! Was hoping to not have to do a separate |

This PR modifies the tophat linking functionality to be consentful and prevent spam and social attack vectors. Now, tophats wishing to link to a new tree submit a request, which must be approved by an admin in the new tree before the linkage takes place.
Additionally, requests can now be submitted by either a) the wearer of an unlinked tophat, or b) the admin of an already-linked tophat. This latter option is new, and creates a pathway for parent trees to move child trees to different places within the parent tree.
Also, accounts that are admins of both the linked tree root and the destination admin hat can now "relink" without needing to first go through the request-approval flow.