msc-smart-contract-auditing/vulnerable-functions-base huggingface dataset:
Vulnerability: Reduce complexity in modifiers related to governance and strategist
Severity: low

Description:
The modifier onlyGovernance:\\n```\\nmodifier onlyGovernance() {\\n    \\_checkGovernance();\\n    \\_;\\n}\\n```\\n\\nCalls the internal function _checkGovernance:\\n```\\nfunction \\_checkGovernance() internal view {\\n    require(msg.sender == governance, "not governance");\\n}\\n```\\n\\nThere is no other case where the internal method `_checkGovernance` is called directly.\\nOne can reduce complexity by removing the internal function and moving its code directly in the modifier. This will increase code size but reduce gas used and code complexity.\\nThere are multiple similar instances:\\n```\\nfunction \\_checkStrategist() internal view {\\n    require(msg.sender == governance || strategists[msg.sender], "not strategist");\\n}\\n\\nmodifier onlyStrategist {\\n    \\_checkStrategist();\\n    \\_;\\n}\\n```\\n\\n```\\nfunction \\_checkGovernance() internal view {\\n    require(msg.sender == governance, "not governance");\\n}\\n\\nmodifier onlyGovernance() {\\n    \\_checkGovernance();\\n    \\_;\\n}\\n```\\n\\n```\\nfunction \\_checkGovernance() internal view {\\n    require(msg.sender == IGaugeController(controller).governance(), "not governance");\\n}\\n\\nmodifier onlyGovernance() {\\n    \\_checkGovernance();\\n    \\_;\\n}\\n```\\n

Impact:

Recommended mitigation:
Consider removing the internal function and including its body in the modifier directly if the code size is not an issue.
Vulnerability: zAuction - incomplete / dead code zWithdraw and zDeposit
Severity: high

Description:
The code generally does not appear to be production-ready. The methods `zWithdraw` and `zDeposit` do not appear to be properly implemented. `zWithdraw` rather burns `ETH` balance than withdrawing it for an account (missing transfer) and `zDeposit` manipulates an accounts balance but never receives the `ETH` amount it credits to an account.\\n```\\n    function zDeposit(address to) external payable onlyZauction {\\n        ethbalance[to] = SafeMath.add(ethbalance[to], msg.value);\\n        emit zDeposited(to, msg.value);\\n    }\\n\\n    function zWithdraw(address from, uint256 amount) external onlyZauction {\\n        ethbalance[from] = SafeMath.sub(ethbalance[from], amount);\\n        emit zWithdrew(from, amount);\\n    }\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nobsolete with changes from zer0-os/[email protected]135b2aa removing the `zAccountAccountant`.\\nThe methods do not seem to be used by the zAuction contract. It is highly discouraged from shipping incomplete implementations in productive code. Remove dead/unreachable code. Fix the implementations to perform proper accounting before reintroducing them if they are called by zAuction.
Vulnerability: zAuction - Unpredictable behavior for users due to admin front running or general bad timing
Severity: high

Description:
An administrator of `zAuctionAccountant` contract can update the `zAuction` contract without warning. This has the potential to violate a security goal of the system.\\nSpecifically, privileged roles could use front running to make malicious changes just ahead of incoming transactions, or purely accidental negative effects could occur due to the unfortunate timing of changes.\\nIn general users of the system should have assurances about the behavior of the action they're about to take.\\nupdating the `zAuction` takes effect immediately. This has the potential to fail acceptance of bids by sellers on the now outdated `zAuction` contract as interaction with the accountant contract is now rejected. This forces bidders to reissue their bids in order for the seller to be able to accept them using the Accountant contract. This may also be used by admins to selectively censor the acceptance of accountant based bids by changing the active `zAuction` address.\\n```\\n    function SetZauction(address zauctionaddress) external onlyAdmin{\\n        zauction = zauctionaddress;\\n        emit ZauctionSet(zauctionaddress);\\n    }\\n\\n    function SetAdmin(address newadmin) external onlyAdmin{\\n        admin = newadmin;\\n        emit AdminSet(msg.sender, newadmin);\\n    }\\n```\\n\\nUpgradeable contracts may introduce the same unpredictability issues where the proxyUpgradeable owner may divert execution to a new zNS registrar implementation selectively for certain transactions or without prior notice to users.

Impact:

Recommended mitigation:
The underlying issue is that users of the system can't be sure what the behavior of a function call will be, and this is because the behavior can change at any time.\\nWe recommend giving the user advance notice of changes with a time lock. For example, make all system-parameter and upgrades require two steps with a mandatory time window between them. The first step merely broadcasts to users that a particular change is coming, and the second step commits that change after a suitable waiting period. This allows users that do not accept the change to withdraw immediately.\\nValidate arguments before updating contract addresses (at least != current/0x0). Consider implementing a 2-step admin ownership transfer (transfer+accept) to avoid losing control of the contract by providing the wrong `ETH` address.
Vulnerability: zAuction - pot. initialization fronrunning and unnecessary init function
Severity: medium

Description:
The `zAuction` initialization method is unprotected and while only being executable once, can be called by anyone. This might allow someone to monitor the mempool for new deployments of this contract and fron-run the initialization to initialize it with different parameters.\\nA mitigating factor is that this condition can be detected by the deployer as subsequent calls to `init()` will fail.\\nNote: this doesn't adhere to common interface naming convention/oz naming convention where this method would be called `initialize`.\\nNote: that zNS in contrast relies on ou/initializable pattern with proper naming.\\nNote: that this function might not be necessary at all and should be replaced by a constructor instead, as the contract is not used with a proxy pattern.\\n```\\nfunction init(address accountantaddress) external {\\n    require(!initialized);\\n    initialized = true;\\n    accountant = zAuctionAccountant(accountantaddress);\\n}\\n```\\n

Impact:

Recommended mitigation:
The contract is not used in a proxy pattern, hence, the initialization should be performed in the `constructor` instead.
Vulnerability: zAuction - unclear upgrade path
Severity: medium

Description:
`zAuction` appears to implement an upgrade path for the auction system via `zAuctionAccountant`. `zAuction` itself does not hold any value. The `zAuctionAccountant` can be configured to allow only one `zAution` contract to interact with it. The update of the contract reference takes effect immediately (https://github.com/ConsenSys/zer0-zauction-audit-2021-05/issues/7).\\nAcceptance of bids via the accountant on the old contract immediately fail after an admin updates the referenced `zAuction` contract while `WETH` bids may still continue. This may create an unfavorable scenario where two contracts may be active in parallel accepting `WETH` bids.\\nIt should also be noted that 2nd layer bids (signed data) using the accountant for the old contract will not be acceptable anymore.\\n```\\nfunction SetZauction(address zauctionaddress) external onlyAdmin{\\n    zauction = zauctionaddress;\\n    emit ZauctionSet(zauctionaddress);\\n}\\n```\\n

Impact:

Recommended mitigation:
Consider re-thinking the upgrade path. Avoid keeping multiple versions of the auction contact active.
Vulnerability: zAuction, zNS - gas griefing by spamming offchain fake bids  Acknowledged
Severity: medium

Description:
The execution status of both `zAuction.acceptBid` and `StakingController.fulfillDomainBid` transactions depend on the bidder, as his approval is needed, his signature is being validated, etc. However, these transactions can be submitted by accounts that are different from the bidder account, or for accounts that do not have the required funds/deposits available, luring the account that has to perform the on-chain call into spending gas on a transaction that is deemed to fail (gas griefing). E.g. posting high-value fake bids for zAuction without having funds deposited or `WETH` approved.\\n```\\n  function fulfillDomainBid(\\n  uint256 parentId,\\n  uint256 bidAmount,\\n  uint256 royaltyAmount,\\n  string memory bidIPFSHash,\\n  string memory name,\\n  string memory metadata,\\n  bytes memory signature,\\n  bool lockOnCreation,\\n  address recipient\\n) external {\\n  bytes32 recoveredBidHash = createBid(parentId, bidAmount, bidIPFSHash, name);\\n  address recoveredBidder = recover(recoveredBidHash, signature);\\n  require(recipient == recoveredBidder, "ZNS: bid info doesnt match/exist");\\n  bytes32 hashOfSig = keccak256(abi.encode(signature));\\n  require(approvedBids[hashOfSig] == true, "ZNS: has been fullfilled");\\n  infinity.safeTransferFrom(recoveredBidder, controller, bidAmount);\\n  uint256 id = registrar.registerDomain(parentId, name, controller, recoveredBidder);\\n  registrar.setDomainMetadataUri(id, metadata);\\n  registrar.setDomainRoyaltyAmount(id, royaltyAmount);\\n  registrar.transferFrom(controller, recoveredBidder, id);\\n  if (lockOnCreation) {\\n    registrar.lockDomainMetadataForOwner(id);\\n  }\\n  approvedBids[hashOfSig] = false;\\n  emit DomainBidFulfilled(\\n    metadata,\\n    name,\\n    recoveredBidder,\\n    id,\\n    parentId\\n  );\\n}\\n```\\n\\n```\\nfunction acceptBid(bytes memory signature, uint256 rand, address bidder, uint256 bid, address nftaddress, uint256 tokenid) external {\\n    address recoveredbidder = recover(toEthSignedMessageHash(keccak256(abi.encode(rand, address(this), block.chainid, bid, nftaddress, tokenid))), signature);\\n    require(bidder == recoveredbidder, 'zAuction: incorrect bidder');\\n    require(!randUsed[rand], 'Random nonce already used');\\n    randUsed[rand] = true;\\n    IERC721 nftcontract = IERC721(nftaddress);\\n    accountant.Exchange(bidder, msg.sender, bid);\\n    nftcontract.transferFrom(msg.sender, bidder, tokenid);\\n    emit BidAccepted(bidder, msg.sender, bid, nftaddress, tokenid);\\n}\\n```\\n

Impact:

Recommended mitigation:
Revert early for checks that depend on the bidder before performing gas-intensive computations.\\nConsider adding a dry-run validation for off-chain components before transaction submission.
Vulnerability: zAuction - hardcoded ropsten token address
Severity: low

Description:
The auction contract hardcodes the WETH ERC20 token address. this address will not be functional when deploying to mainnet.\\n```\\n    IERC20 weth = IERC20(address(0xc778417E063141139Fce010982780140Aa0cD5Ab)); // rinkeby weth\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nAddressed with zer0-os/[email protected]135b2aa and the following statement:\\n5.30 weth address in constructor\\nNote: does not perform input validation as recommended\\nConsider taking the used `WETH` token address as a constructor argument. Avoid code changes to facilitate testing! Perform input validation on arguments rejecting `address(0x0)` to facilitate the detection of potential misconfiguration in the deployment pipeline.
Vulnerability: zAuction - accountant allows zero value withdrawals/deposits/exchange
Severity: low

Description:
Zero value transfers effectively perform a no-operation sometimes followed by calling out to the recipient of the withdrawal.\\nA transfer where `from==to` or where the value is `0` is ineffective.\\n```\\nfunction Withdraw(uint256 amount) external {\\n    ethbalance[msg.sender] = SafeMath.sub(ethbalance[msg.sender], amount);\\n    payable(msg.sender).transfer(amount);\\n    emit Withdrew(msg.sender, amount);\\n}\\n```\\n\\n```\\nfunction Deposit() external payable {\\n    ethbalance[msg.sender] = SafeMath.add(ethbalance[msg.sender], msg.value);\\n    emit Deposited(msg.sender, msg.value);\\n}\\n```\\n\\n```\\n    function zDeposit(address to) external payable onlyZauction {\\n        ethbalance[to] = SafeMath.add(ethbalance[to], msg.value);\\n        emit zDeposited(to, msg.value);\\n    }\\n\\n    function zWithdraw(address from, uint256 amount) external onlyZauction {\\n        ethbalance[from] = SafeMath.sub(ethbalance[from], amount);\\n        emit zWithdrew(from, amount);\\n    }\\n\\n    function Exchange(address from, address to, uint256 amount) external onlyZauction {\\n        ethbalance[from] = SafeMath.sub(ethbalance[from], amount);\\n        ethbalance[to] = SafeMath.add(ethbalance[to], amount);\\n        emit zExchanged(from, to, amount);\\n    }\\n```\\n

Impact:

Recommended mitigation:
Consider rejecting ineffective withdrawals (zero value) or at least avoid issuing a zero value `ETH` transfers. Avoid emitting successful events for ineffective calls to not trigger 3rd party components on noop's.
Vulnerability: zAuction - seller should not be able to accept their own bid
Severity: low

Description:
A seller can accept their own bid which is an ineffective action that is emitting an event.\\n```\\nfunction acceptBid(bytes memory signature, uint256 rand, address bidder, uint256 bid, address nftaddress, uint256 tokenid) external {\\n    address recoveredbidder = recover(toEthSignedMessageHash(keccak256(abi.encode(rand, address(this), block.chainid, bid, nftaddress, tokenid))), signature);\\n    require(bidder == recoveredbidder, 'zAuction: incorrect bidder');\\n    require(!randUsed[rand], 'Random nonce already used');\\n    randUsed[rand] = true;\\n    IERC721 nftcontract = IERC721(nftaddress);\\n    accountant.Exchange(bidder, msg.sender, bid);\\n    nftcontract.transferFrom(msg.sender, bidder, tokenid);\\n    emit BidAccepted(bidder, msg.sender, bid, nftaddress, tokenid);\\n}\\n\\n/// @dev 'true' in the hash here is the eth/weth switch\\nfunction acceptWethBid(bytes memory signature, uint256 rand, address bidder, uint256 bid, address nftaddress, uint256 tokenid) external {\\n    address recoveredbidder = recover(toEthSignedMessageHash(keccak256(abi.encode(rand, address(this), block.chainid, bid, nftaddress, tokenid, true))), signature);\\n    require(bidder == recoveredbidder, 'zAuction: incorrect bidder');\\n    require(!randUsed[rand], 'Random nonce already used');\\n    randUsed[rand] = true;\\n    IERC721 nftcontract = IERC721(nftaddress);\\n    weth.transferFrom(bidder, msg.sender, bid);\\n    nftcontract.transferFrom(msg.sender, bidder, tokenid);\\n    emit WethBidAccepted(bidder, msg.sender, bid, nftaddress, tokenid);\\n}\\n```\\n

Impact:

Recommended mitigation:
Disallow transfers to self.
Vulnerability: zBanc - DynamicLiquidTokenConverter ineffective reentrancy protection
Severity: high

Description:
`reduceWeight` calls `_protected()` in an attempt to protect from reentrant calls but this check is insufficient as it will only check for the `locked` statevar but never set it. A potential for direct reentrancy might be present when an erc-777 token is used as reserve.\\nIt is assumed that the developer actually wanted to use the `protected` modifier that sets the lock before continuing with the method.\\n```\\nfunction reduceWeight(IERC20Token \\_reserveToken)\\n    public\\n    validReserve(\\_reserveToken)\\n    ownerOnly\\n{\\n    \\_protected();\\n```\\n\\n```\\ncontract ReentrancyGuard {\\n    // true while protected code is being executed, false otherwise\\n    bool private locked = false;\\n\\n    /\\*\\*\\n \\* @dev ensures instantiation only by sub-contracts\\n \\*/\\n    constructor() internal {}\\n\\n    // protects a function against reentrancy attacks\\n    modifier protected() {\\n        \\_protected();\\n        locked = true;\\n        \\_;\\n        locked = false;\\n    }\\n\\n    // error message binary size optimization\\n    function \\_protected() internal view {\\n        require(!locked, "ERR\\_REENTRANCY");\\n    }\\n}\\n```\\n

Impact:

Recommended mitigation:
To mitigate potential attack vectors from reentrant calls remove the call to `_protected()` and decorate the function with `protected` instead. This will properly set the lock before executing the function body rejecting reentrant calls.
Vulnerability: zBanc - DynamicLiquidTokenConverter input validation
Severity: medium

Description:
Check that the value in `PPM` is within expected bounds before updating system settings that may lead to functionality not working correctly. For example, setting out-of-bounds values for `stepWeight` or `setMinimumWeight` may make calls to `reduceWeight` fail. These values are usually set in the beginning of the lifecycle of the contract and misconfiguration may stay unnoticed until trying to reduce the weights. The settings can be fixed, however, by setting the contract inactive and updating it with valid settings. Setting the contract to inactive may temporarily interrupt the normal operation of the contract which may be unfavorable.\\nBoth functions allow the full `uint32` range to be used, which, interpreted as `PPM` would range from `0%` to `4.294,967295%`\\n```\\nfunction setMinimumWeight(uint32 \\_minimumWeight)\\n    public\\n    ownerOnly\\n    inactive\\n{\\n    //require(\\_minimumWeight > 0, "Min weight 0");\\n    //\\_validReserveWeight(\\_minimumWeight);\\n    minimumWeight = \\_minimumWeight;\\n    emit MinimumWeightUpdated(\\_minimumWeight);\\n}\\n```\\n\\n```\\nfunction setStepWeight(uint32 \\_stepWeight)\\n    public\\n    ownerOnly\\n    inactive\\n{\\n    //require(\\_stepWeight > 0, "Step weight 0");\\n    //\\_validReserveWeight(\\_stepWeight);\\n    stepWeight = \\_stepWeight;\\n    emit StepWeightUpdated(\\_stepWeight);\\n}\\n```\\n

Impact:

Recommended mitigation:
Reintroduce the checks for `_validReserveWeight` to check that a percent value denoted in `PPM` is within valid bounds `_weight > 0 && _weight <= PPM_RESOLUTION`. There is no need to separately check for the value to be `>0` as this is already ensured by `_validReserveWeight`.\\nNote that there is still room for misconfiguration (step size too high, min-step too high), however, this would at least allow to catch obviously wrong and often erroneously passed parameters early.
Vulnerability: zBanc - DynamicLiquidTokenConverter consider using PPM_RESOLUTION instead of hardcoding integer literals
Severity: low

Description:
`getMarketCap` calculates the reserve's market capitalization as `reserveBalance * `1e6` / weight` where `1e6` should be expressed as the constant `PPM_RESOLUTION`.\\n```\\nfunction getMarketCap(IERC20Token \\_reserveToken)\\n    public\\n    view\\n    returns(uint256)\\n{\\n    Reserve storage reserve = reserves[\\_reserveToken];\\n    return reserveBalance(\\_reserveToken).mul(1e6).div(reserve.weight);\\n}\\n```\\n

Impact:

Recommended mitigation:
Avoid hardcoding integer literals directly into source code when there is a better expression available. In this case `1e6` is used because weights are denoted in percent to base `PPM_RESOLUTION` (=100%).
Vulnerability: zBanc - DynamicLiquidTokenConverter avoid potential converter type overlap with bancor  Acknowledged
Severity: low

Description:
The system is forked frombancorprotocol/contracts-solidity. As such, it is very likely that security vulnerabilities reported to bancorprotocol upstream need to be merged into the zer0/zBanc fork if they also affect this codebase. There is also a chance that security fixes will only be available with feature releases or that the zer0 development team wants to merge upstream features into the zBanc codebase.\\nzBanc introduced `converterType=3` for the `DynamicLiquidTokenConverter` as `converterType=1` and `converterType=2` already exist in the bancorprotocol codebase. Now, since it is unclear if `DynamicLiquidTokenConverter` will be merged into bancorprotocol there is a chance that bancor introduces new types that overlap with the `DynamicLiquidTokenConverter` converter type (3). It is therefore suggested to map the `DynamicLiquidTokenConverter` to a converterType that is unlikely to create an overlap with the system it was forked from. E.g. use converter type id `1001` instead of `3` (Note: converterType is an uint16).\\nNote that the current master of the bancorprotocol already appears to defined converterType 3 and 4: https://github.com/bancorprotocol/contracts-solidity/blob/5f4c53ebda784751c3a90b06aa2c85e9fdb36295/solidity/test/helpers/Converter.js#L51-L54\\nThe new custom converter\\n```\\nfunction converterType() public pure override returns (uint16) {\\n    return 3;\\n}\\n```\\n\\nConverterTypes from the bancor base system\\n```\\nfunction converterType() public pure override returns (uint16) {\\n    return 1;\\n}\\n```\\n\\n```\\n\\*/\\nfunction converterType() public pure override returns (uint16) {\\n    return 2;\\n}\\n```\\n

Impact:

Recommended mitigation:
Choose a converterType id for this custom implementation that does not overlap with the codebase the system was forked from. e.g. `uint16(-1)` or `1001` instead of `3` which might already be used upstream.
Vulnerability: zDAO Token - Specification violation - Snapshots are never taken  Partially Addressed
Severity: high

Description:
Resolution\\nAddressed with zer0-os/[email protected]81946d4 by exposing the `_snapshot()` method to a dedicated snapshot role (likely to be a DAO) and the owner of the contract.\\nWe would like to note that we informed the client that depending on how the snapshot method is used and how predictably snapshots are consumed this might open up a frontrunning vector where someone observing that a `_snapshot()` is about to be taken might sandwich the snapshot call, accumulate a lot of stake (via 2nd markets, lending platforms), and returning it right after it's been taken. The risk of losing funds may be rather low (especially if performed by a miner) and the benefit from a DAO proposal using this snapshot might outweigh it. It is still recommended to increase the number of snapshots taken or take them on a regular basis (e.g. with every first transaction to the contract in a block) to make it harder to sandwich the snapshot taking.\\nAccording to the zDAO Token specification the DAO token should implement a snapshot functionality to allow it being used for DAO governance votings.\\nAny transfer, mint, or burn operation should result in a snapshot of the token balances of involved users being taken.\\nWhile the corresponding functionality is implemented and appears to update balances for snapshots, `_snapshot()` is never called, therefore, the snapshot is never taken. e.g. attempting to call `balanceOfAt` always results in an error as no snapshot is available.\\n```\\ncontract ZeroDAOToken is\\n  OwnableUpgradeable,\\n  ERC20Upgradeable,\\n  ERC20PausableUpgradeable,\\n  ERC20SnapshotUpgradeable\\n{\\n```\\n\\n```\\n\\_updateAccountSnapshot(sender);\\n```\\n\\nNote that this is an explicit requirement as per specification but unit tests do not seem to attempt calls to `balanceOfAt` at all.

Impact:

Recommended mitigation:
Actually, take a snapshot by calling `_snapshot()` once per block when executing the first transaction in a new block. Follow the openzeppeling documentation for ERC20Snapshot.