# Hidden Hand Audit Report ## Introduction This audit was requested by Redacted team and was conducted by [kebabsec](https://twitter.com/kebabsec) members [sai](https://twitter.com/sigh242), [FlameHorizon](https://twitter.com/FlameHorizon1) and [okkothejawa](https://twitter.com/okkothejawa). As always, Redacted team delivers with easy to understand, clean and neat code. ****Note: This report does not provide any guarantee or warranty of security for the project.**** ## Scope This audit includes the following contracts as in scope: 1. [BribeBase.sol](https://github.com/redacted-cartel/hidden-hand/blob/main/contracts/BribeBase.sol) 2. [BribeVault.sol](https://github.com/redacted-cartel/hidden-hand/blob/main/contracts/BribeVault.sol) 3. [HummusBribe.sol](https://github.com/redacted-cartel/hidden-hand/blob/main/contracts/HummusBribe.sol) Branch: [redacted-cartel/hidden-hand/main](https://github.com/redacted-cartel/hidden-hand) ---- ## Table of Contents 1. [BribeBase.sol#L320-L324: dead code function `setRewardForwarding`](#orga9b9f8b) 2. [BribeBase.sol#L243 - redundant token address check](#org65a16f3) 3. [BribeVault.sol#L9-L13 - Redundant Interface `IRewardDistributor`.](#org259c19e) 4. [BribeVault.sol#L30 & L80-L81 - Unnecessary assignment of `_feeMax`](#feeMax) 5. [BribeVault.sol#L92 & BribeBase.sol #L47 - Deployer addresses have admin privileges](#deployer) <a id="orga9b9f8b"></a> ### 1. [INFO] [BribeBase.sol#L320-L324 Dead code function `setRewardForwarding`](https://github.com/redacted-cartel/hidden-hand/blob/main/contracts/BribeBase.sol#L320-L324) ****Description****: - This function allows voters to opt in or out of reward forwarding, setting `rewardForwarding[msg.caller]` to any address. - However the mapping `rewardForwarding` is not used anywhere, which unnecessarily wastes gas. **Suggestion:** - Assuming no other contracts access the `rewardForwarding` mapping, removing redundant function may decrease the gas cost. <a id="org65a16f3"></a> ### 2. [GAS] [BribeBase.sol#L243 - redundant token zero address check](https://github.com/redacted-cartel/hidden-hand/blob/main/contracts/BribeBase.sol#L243) ****Description****: - This check is not needed, as `require(isWhitelistedToken(token), "Token is not whitelisted");` already returns false on address(0). - Removing the check improves gas usage: - **Before change:** *depositBribeERC20 - 173720 gas* - **After change:** *depositBribeERC20 - 173685 gas* 1. [It's not possible to add zero address token to whitelist](https://github.com/redacted-cartel/hidden-hand/blob/main/contracts/BribeBase.sol#L117) 2. [Removing a token occurs without check for address(0), as address 0 can't be added to list](https://github.com/redacted-cartel/hidden-hand/blob/main/contracts/BribeBase.sol#L143) 3. Thus it can be concluded that `isWhitelistedToken` can't return true for address(0) To demonstrate that `isWhitelistedToken` already checks against `address(0)`, a function `removeWhitelistTokens` is used as an example: ```solidity ├─ [52994] BribeBase::addWhitelistTokens([0x0000000000000000000000000000000000000001]) │ ├─ emit AddWhitelistTokens(tokens: [0x0000000000000000000000000000000000000001]) │ └─ ← () ├─ [3918] BribeBase::removeWhitelistTokens([0x0000000000000000000000000000000000000000]) │ └─ ← "Token not whitelisted" └─ ← "Token not whitelisted" ``` The trace shows `isWhitelistedToken` results in revert for address(0), therefore line 243: `require(token != address(0), "Invalid token");` is not necessary. ****Suggestion****: Remove the `require(token != address(0), "Invalid token")`check. <a id="org259c19e"></a> ### 3. [INFO] [BribeVault.sol#L9-L13 - Redundant Interface `IRewardDistributor`](https://github.com/redacted-cartel/hidden-hand/blob/main/contracts/BribeVault.sol#L9-L13) **Description**: Interface is not inherited and can be removed. **Suggestion**: Remove the interface. <a id="feeMax"></a> ### 4. [INFO] [BribeVault.sol#L30 & L80-L81 - Unnecessary assignment of `_feeMax`](https://github.com/redacted-cartel/hidden-hand/blob/main/contracts/BribeVault.sol#L80) **Description**: We feel that is perhaps unnecessary to have `require(_feeMax < FEE_DIVISOR / 2, "Invalid _feeMax");` and to have a maximum `FEE_MAX` as you can't really lower it or increase it after deployment, since there's no function to change that variable, and there is no incentive to make `FEE_MAX` lower than the limit that is set by the require check. **Suggestion**: This is obviously irrelevant on how the code works, but if `FEE_MAX` is already bound by a constant divided by two, it seemed to us that it would make sense to also make it a constant, or just have a function to change `FEE_MAX` within those bounds. <a id="deployer"></a> ### 5. **[INFO] [BribeVault.sol#L92 & BribeBase.sol #L47 - Deployer addresses have admin privileges](https://github.com/redacted-cartel/hidden-hand/blob/main/contracts/BribeVault.sol#L92)** **Description**: In both `BribeVault` and `BribeBase` deployers are granted admin privileges, thus an EOA may get admin privileges, and this is not ideal. **Suggestion**: For more ideal security posture, either pass a multi-sig address as a parameter to be set as `DEFAULT_ADMIN_ROLE` and/or implement a two-step ownership transfer mechanism to transfer the ownership to a multi-sig later.