msc-smart-contract-auditing/vulnerable-functions-base huggingface dataset:
Vulnerability: ID validation check missing for installDandelionApps
Severity: low

Description:
`DandelionOrg` allows users to kickstart an Aragon organization by using a dao template. There are two primary functions to instantiate an org: `newTokenAndBaseInstance`, and `installDandelionApps`. Both functions accept a parameter, `string _id`, meant to represent an ENS subdomain that will be assigned to the new org during the instantiation process. The two functions are called independently, but depend on each other.\\nIn `newTokenAndBaseInstance`, a sanity check is performed on the `_id` parameter, which ensures the `_id` length is nonzero:\\n```\\n\\_validateId(\\_id);\\n```\\n\\nNote that the value of `_id` is otherwise unused in `newTokenAndBaseInstance`.\\nIn `installDandelionApps`, this check is missing. The check is only important in this function, since it is in `installDandelionApps` that the ENS subdomain registration is actually performed.

Impact:

Recommended mitigation:
Use `_validateId` in `installDandelionApps` rather than `newTokenAndBaseInstance`. Since the `_id` parameter is otherwise unused in `newTokenAndBaseInstance`, it can be removed.\\nAlternatively, the value of the submitted `_id` could be cached between calls and validated in `newTokenAndBaseInstance`, similarly to `newToken`.
Vulnerability: EOPBCTemplate - AppId of BalanceRedirectPresale should be different from AragonBlack/Presale namehash to avoid collisions
Severity: high

Description:
The template references the new presale contract with `apmNamehash` `0x5de9bbdeaf6584c220c7b7f1922383bcd8bbcd4b48832080afd9d5ebf9a04df5`. However, this namehash is already used by the aragonBlack/Presale contract. To avoid confusion and collision a unique `apmNamehash` should be used for this variant of the contract.\\nNote that the contract that is referenced from an `apmNamehash` is controlled by the `ENS` resolver that is configured when deploying the template contract. Using the same namehash for both variants of the contract does not allow a single registry to simultaneously provide both variants of the contract and might lead to confusion as to which application is actually deployed. This also raises the issue that the `ENS` registry must be verified before actually using the contract as a malicious registry could force the template to deploy potentially malicious applications.\\naragonOne/Fundraising:\\n```\\nbytes32   private constant PRESALE\\_ID                    = 0x5de9bbdeaf6584c220c7b7f1922383bcd8bbcd4b48832080afd9d5ebf9a04df5;\\n```\\n\\naragonBlack/Fundraising:\\n```\\nbytes32   private constant PRESALE\\_ID             = 0x5de9bbdeaf6584c220c7b7f1922383bcd8bbcd4b48832080afd9d5ebf9a04df5;\\n```\\n\\n`bytes32 private constant PRESALE_ID = 0x5de9bbdeaf6584c220c7b7f1922383bcd8bbcd4b48832080afd9d5ebf9a04df5;`

Impact:

Recommended mitigation:
Create a new `apmNamehash` for `BalanceRedirectPresale`.
Vulnerability: BalanceRedirectPresale - Presale can be extended indefinitely  Won't Fix
Severity: high

Description:
The `OPEN_ROLE` can indefinitely extend the Presale even after users contributed funds to it by adjusting the presale period. The period might be further manipulated to avoid that token trading in the MarketMaker is opened.\\n```\\nfunction setPeriod(uint64 \\_period) external auth(OPEN\\_ROLE) {\\n    \\_setPeriod(\\_period);\\n}\\n```\\n\\n```\\nfunction \\_setPeriod(uint64 \\_period) internal {\\n    require(\\_period > 0, ERROR\\_TIME\\_PERIOD\\_ZERO);\\n    require(openDate == 0 || openDate + \\_period > getTimestamp64(), ERROR\\_INVALID\\_TIME\\_PERIOD);\\n    period = \\_period;\\n}\\n```\\n

Impact:

Recommended mitigation:
Do not allow to extend the presale after funds have been contributed to it or only allow period adjustments in `State.PENDING`.
Vulnerability: BalanceRedirectPresale - setPeriod uint64 overflow in validation check
Severity: medium

Description:
`setPeriod()` allows setting an arbitrary Presale starting date. The method can be called by an entity with the `OPEN_ROLE` permission. Providing a large enough value for `uint64 _period` can overflow the second input validation check. The result is unwanted behaviour where for relatively large values of `period` the require might fail because the overflow `openDate + _period` is less than or equal the current timestamp (getTimestamp64()) but if high enough it still might succeed because `openDate + _period` is higher than the current timestamp. The overflow has no effect on the presale end as it is calculated against `_timeSinceOpen`.\\n```\\nfunction \\_setPeriod(uint64 \\_period) internal {\\n    require(\\_period > 0, ERROR\\_TIME\\_PERIOD\\_ZERO);\\n    require(openDate == 0 || openDate + \\_period > getTimestamp64(), ERROR\\_INVALID\\_TIME\\_PERIOD);\\n    period = \\_period;\\n}\\n```\\n\\n

Impact:

Recommended mitigation:
Resolution\\nFixed with aragonone/[email protected]bafe100 by performing the addition using `SafeMath`.\\nUse `SafeMath` which is already imported to protect from overflow scenarios.
Vulnerability: EOPBCTemplate - misleading method names _cacheFundraisingApps and _cacheFundraisingParams
Severity: low

Description:
The methods `_cacheFundraisingApps` and `_cacheFundraisingParams` suggest that parameters are cached as state variables in the contract similar to the multi-step deployment contract used for AragonBlack/Fundraising. However, the methods are just returning memory structs.\\n```\\nfunction \\_cacheFundraisingApps(\\n    Agent          \\_reserve,\\n    Presale        \\_presale,\\n    MarketMaker    \\_marketMaker,\\n    Tap            \\_tap,\\n    Controller     \\_controller,\\n    TokenManager   \\_tokenManager\\n)\\n    internal\\n    returns (FundraisingApps memory fundraisingApps)\\n{\\n    fundraisingApps.reserve            = \\_reserve;\\n    fundraisingApps.presale            = \\_presale;\\n    fundraisingApps.marketMaker        = \\_marketMaker;\\n    fundraisingApps.tap                = \\_tap;\\n    fundraisingApps.controller         = \\_controller;\\n    fundraisingApps.bondedTokenManager = \\_tokenManager;\\n}\\n\\nfunction \\_cacheFundraisingParams(\\n    address       \\_owner,\\n    string        \\_id,\\n    ERC20         \\_collateralToken,\\n    MiniMeToken   \\_bondedToken,\\n    uint64        \\_period,\\n    uint256       \\_exchangeRate,\\n    uint64        \\_openDate,\\n    uint256       \\_reserveRatio,\\n    uint256       \\_batchBlocks,\\n    uint256       \\_slippage\\n)\\n    internal\\n    returns (FundraisingParams fundraisingParams)\\n{\\n    fundraisingParams = FundraisingParams({\\n        owner:           \\_owner,\\n        id:              \\_id,\\n        collateralToken: \\_collateralToken,\\n        bondedToken:     \\_bondedToken,\\n        period:          \\_period,\\n        exchangeRate:    \\_exchangeRate,\\n        openDate:        \\_openDate,\\n        reserveRatio:    \\_reserveRatio,\\n        batchBlocks:     \\_batchBlocks,\\n        slippage:        \\_slippage\\n    });\\n}\\n```\\n

Impact:

Recommended mitigation:
The functions are only called once throughout the deployment process. The structs can therefore be created directly in the main method. Otherwise rename the functions to properly reflect their purpose.
Vulnerability: EOPBCTemplate - inconsistent storage location declaration
Severity: low

Description:
`_cacheFundraisingParams()` does not explicitly declare the return value memory location.\\n```\\nfunction \\_cacheFundraisingParams(\\n    address       \\_owner,\\n    string        \\_id,\\n    ERC20         \\_collateralToken,\\n    MiniMeToken   \\_bondedToken,\\n    uint64        \\_period,\\n    uint256       \\_exchangeRate,\\n    uint64        \\_openDate,\\n    uint256       \\_reserveRatio,\\n    uint256       \\_batchBlocks,\\n    uint256       \\_slippage\\n)\\n    internal\\n    returns (FundraisingParams fundraisingParams)\\n```\\n\\n`_cacheFundraisingApps()` explicitly declares to return a copy of the storage struct.\\n```\\nfunction \\_cacheFundraisingApps(\\n    Agent          \\_reserve,\\n    Presale        \\_presale,\\n    MarketMaker    \\_marketMaker,\\n    Tap            \\_tap,\\n    Controller     \\_controller,\\n    TokenManager   \\_tokenManager\\n)\\n    internal\\n    returns (FundraisingApps memory fundraisingApps)\\n{\\n    fundraisingApps.reserve            = \\_reserve;\\n    fundraisingApps.presale            = \\_presale;\\n    fundraisingApps.marketMaker        = \\_marketMaker;\\n    fundraisingApps.tap                = \\_tap;\\n    fundraisingApps.controller         = \\_controller;\\n    fundraisingApps.bondedTokenManager = \\_tokenManager;\\n}\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nFixed with aragonone/[email protected]bafe100 by adding the missing storage location declaration.\\nStorage declarations should be consistent.
Vulnerability: EOPBCTemplate - EtherTokenConstant is never used
Severity: low

Description:
The constant value `EtherTokenConstant.ETH` is never used.\\n```\\ncontract EOPBCTemplate is EtherTokenConstant, BaseTemplate {\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nFixed with aragonone/[email protected]bafe100 by removing the `EtherTokenConstant` dependency.\\nRemove all references to `EtherTokenConstant`.
Vulnerability: Staking node can be inappropriately removed from the tree
Severity: high

Description:
The following code in `OrchidDirectory.pull()` is responsible for reattaching a child from a removed tree node:\\n```\\nif (name(stake.left\\_) == key) {\\n    current.right\\_ = stake.right\\_;\\n    current.after\\_ = stake.after\\_;\\n} else {\\n    current.left\\_ = stake.left\\_;\\n    current.before\\_ = stake.before\\_;\\n}\\n```\\n\\nThe condition name(stake.left_) == `key` can never hold because `key` is the `key` for `stake` itself.\\nThe result of this bug is somewhat catastrophic. The child is not reattached, but it still has a link to the rest of the tree via its ‘parent_' pointer. This means reducing the stake of that node can underflow the ancestors' before/after amounts, leading to improper random selection or failing altogether.\\nThe node replacing the removed node also ends up with itself as a child, which violates the basic tree structure and is again likely to produce integer underflows and other failures.

Impact:

Recommended mitigation:
As a simple fix, use `if(name(stake.left_) == name(last))` as already suggested by the development team when this bug was first shared.\\nTwo suggestions for better long-term fixes:\\nUse a strict interface for tree operations. It should be impossible to update a node's parent without simultaneously updating that parent's child pointer.\\nAs suggested in (https://github.com/ConsenSys/orchid-audit-2019-10/issues/7), simplify the logic in `pull()` to avoid this logic altogether.
Vulnerability: Use consistent staker, stakee ordering in OrchidDirectory
Severity: low

Description:
```\\nfunction lift(bytes32 key, Stake storage stake, uint128 amount, address stakee, address staker) private {\\n```\\n\\n`OrchidDirectory.lift()` has a parameter `stakee` that precedes `staker`, while the rest of the code always places `staker` first. Because Solidity doesn't have named parameters, it's a good idea to use a consistent ordering to avoid mistakes.

Impact:

Recommended mitigation:
Resolution\\nThis is fixed in OrchidProtocol/[email protected]1cfef88.\\nSwitch `lift()` to follow the “staker then stakee” ordering convention of the rest of the contract.
Vulnerability: In OrchidDirectory.step() and OrchidDirectory.lift(), use a signed amount  Won't Fix
Severity: low

Description:
`step()` and `lift()` both accept a `uint128` parameter called `amount`. This `amount` is added to various struct fields, which are also of type `uint128`.\\nThe contract intentionally underflows this `amount` to represent negative numbers. This is roughly equivalent to using a signed integer, except that:\\nUnsigned integers aren't sign extended when they're cast to a larger integer type, so care must be taken to avoid this.\\nTools that look for integer overflow/underflow will detect this possibility as a bug. It's then hard to determine which overflows are intentional and which are not.\\n```\\nlift(key, stake, -amount, stakee, staker);\\n```\\n\\n```\\nstep(key, stake, -current.amount\\_, current.parent\\_);\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nThe variables in question are now uint256s. The amount of type casts that would be needed in case the recommended change was implemented would defeat the purpose of simplification.\\nUse `int128` instead, and ensure that amounts can never exceed the maximum `int128` value. (This is trivially achieved by limiting the total number of tokens that can exist.)
Vulnerability: Document that math in OrchidDirectory assumes a maximum number of tokens
Severity: low

Description:
`OrchidDirectory` relies on mathematical operations being unable to overflow due to the particular ERC20 token being used being capped at less than `2**128`.\\nThe following code in `step()` assumes that no before/after amount can reach 2**128:\\n```\\nif (name(stake.left\\_) == key)\\n    stake.before\\_ += amount;\\nelse\\n    stake.after\\_ += amount;\\n```\\n\\nThe following code in `lift()` assumes that no staked amount (or total amount for a given stakee) can reach 2**128:\\n```\\nuint128 local = stake.amount\\_;\\nlocal += amount;\\nstake.amount\\_ = local;\\nemit Update(staker, stakee, local);\\n\\nuint128 global = stakees\\_[stakee].amount\\_;\\nglobal += amount;\\nstakees\\_[stakee].amount\\_ = global;\\n```\\n\\nThe following code in `have()` assumes that the total amount staked cannot reach 2**128:\\n```\\nreturn stake.before\\_ + stake.after\\_ + stake.amount\\_;\\n```\\n

Impact:

Recommended mitigation:
Document this assumption in the form of code comments where potential overflows exist.\\nConsider also asserting the ERC20 token's total supply in the constructor to attempt to block using a token that violates this constraint and/or checking in `push()` that the total amount staked will remain less than `2**128`. This recommendation is in line with the mitigation proposed for issue 6.7.
Vulnerability: Fees can be changed during the batch
Severity: high

Description:
Shareholders can vote to change the fees. For buy orders, fees are withdrawn immediately when order is submitted and the only risk is frontrunning by the shareholder's voting contract.\\nFor sell orders, fees are withdrawn when a trader claims an order and withdraws funds in `_claimSellOrder` function:\\n```\\nif (fee > 0) {\\n    reserve.transfer(\\_collateral, beneficiary, fee);\\n}\\n```\\n\\nFees can be changed between opening order and claiming this order which makes the fees unpredictable.

Impact:

Recommended mitigation:
Resolution\\nFixed with AragonBlack/[email protected]0941f53 by storing current fee in meta batch.\\nFees for an order should not be updated during its lifetime.
Vulnerability: Bancor formula should not be updated during the batch
Severity: high

Description:
Shareholders can vote to change the bancor formula contract. That can make a price in the current batch unpredictable.\\n```\\nfunction updateFormula(IBancorFormula \\_formula) external auth(UPDATE\\_FORMULA\\_ROLE) {\\n    require(isContract(\\_formula), ERROR\\_CONTRACT\\_IS\\_EOA);\\n\\n    \\_updateFormula(\\_formula);\\n}\\n```\\n

Impact:

Recommended mitigation:
Bancor formula update should be executed in the next batch or with a timelock that is greater than batch duration.
Vulnerability: Maximum slippage shouldn't be updated for the current batch
Severity: high

Description:
When anyone submits a new order, the batch price is updated and it's checked whether the price slippage is acceptable. The problem is that the maximum slippage can be updated during the batch and traders cannot be sure that price is limited as they initially expected.\\n```\\nfunction \\_slippageIsValid(Batch storage \\_batch, address \\_collateral) internal view returns (bool) {\\n    uint256 staticPricePPM = \\_staticPricePPM(\\_batch.supply, \\_batch.balance, \\_batch.reserveRatio);\\n    uint256 maximumSlippage = collaterals[\\_collateral].slippage;\\n```\\n\\nAdditionally, if a maximum slippage is updated to a lower value, some of the orders that should lower the current slippage will also revert.

Impact:

Recommended mitigation:
Save a slippage value on batch initialization and use it during the current batch.
Vulnerability: AragonFundraisingController - an untapped address in toReset can block attempts of opening Trading after presale
Severity: high

Description:
AragonFundraisingController can be initialized with a list of token addresses `_toReset` that are to be reset when trading opens after the presale. These addresses are supposed to be addresses of tapped tokens. However, the list needs to be known when initializing the contract but the tapped tokens are added after initialization when calling `addCollateralToken` (and tapped with _rate>0). This can lead to an inconsistency that blocks `openTrading`.\\n```\\nfor (uint256 i = 0; i < \\_toReset.length; i++) {\\n    require(\\_tokenIsContractOrETH(\\_toReset[i]), ERROR\\_INVALID\\_TOKENS);\\n    toReset.push(\\_toReset[i]);\\n}\\n```\\n\\nIn case a token address makes it into the list of `toReset` tokens that is not tapped it will be impossible to `openTrading` as `tap.resetTappedToken(toReset[i]);` throws for untapped tokens. According to the permission setup in `FundraisingMultisigTemplate` only Controller can call `Marketmaker.open`\\n```\\nfunction openTrading() external auth(OPEN\\_TRADING\\_ROLE) {\\n    for (uint256 i = 0; i < toReset.length; i++) {\\n        tap.resetTappedToken(toReset[i]);\\n    }\\n\\n    marketMaker.open();\\n}\\n```\\n

Impact:

Recommended mitigation:
Instead of initializing the Controller with a list of tapped tokens to be reset when trading opens, add a flag to `addCollateralToken` to indicate that the token should be reset when calling `openTrading`, making sure only tapped tokens are added to this list. This also allows adding tapped tokens that are to be reset at a later point in time.
Vulnerability: [New] Tapped collaterals can be bought by traders  Won't Fix
Severity: medium

Description:
When a trader submits a sell order, `_openSellOrder()` function checks that there are enough tokens in `reserve` by calling `_poolBalanceIsSufficient` function\\n```\\nfunction \\_poolBalanceIsSufficient(address \\_collateral) internal view returns (bool) {\\n    return controller.balanceOf(address(reserve), \\_collateral) >= collateralsToBeClaimed[\\_collateral];\\n}\\n```\\n\\nthe problem is that because `collateralsToBeClaimed[_collateral]` has increased, `controller.balanceOf(address(reserve), _collateral)` could also increase. It happens so because `controller.balanceOf()` function subtracts tapped amount from the reserve's balance.\\n```\\nfunction balanceOf(address \\_who, address \\_token) public view isInitialized returns (uint256) {\\n    uint256 balance = \\_token == ETH ? \\_who.balance : ERC20(\\_token).staticBalanceOf(\\_who);\\n\\n    if (\\_who == address(reserve)) {\\n        return balance.sub(tap.getMaximumWithdrawal(\\_token));\\n    } else {\\n        return balance;\\n    }\\n}\\n```\\n\\nAnd `tap.getMaximumWithdrawal(_token)` could decrease because it depends on `collateralsToBeClaimed[_collateral]`\\n```\\nfunction \\_tappedAmount(address \\_token) internal view returns (uint256) {\\n    uint256 toBeKept = controller.collateralsToBeClaimed(\\_token).add(floors[\\_token]);\\n    uint256 balance = \\_token == ETH ? address(reserve).balance : ERC20(\\_token).staticBalanceOf(reserve);\\n    uint256 flow = (\\_currentBatchId().sub(lastTappedAmountUpdates[\\_token])).mul(rates[\\_token]);\\n    uint256 tappedAmount = tappedAmounts[\\_token].add(flow);\\n    /\\*\\*\\n \\* whatever happens enough collateral should be\\n \\* kept in the reserve pool to guarantee that\\n \\* its balance is kept above the floor once\\n \\* all pending sell orders are claimed\\n \\*/\\n\\n    /\\*\\*\\n \\* the reserve's balance is already below the balance to be kept\\n \\* the tapped amount should be reset to zero\\n \\*/\\n    if (balance <= toBeKept) {\\n        return 0;\\n    }\\n\\n    /\\*\\*\\n \\* the reserve's balance minus the upcoming tap flow would be below the balance to be kept\\n \\* the flow should be reduced to balance - toBeKept\\n \\*/\\n    if (balance <= toBeKept.add(tappedAmount)) {\\n        return balance.sub(toBeKept);\\n    }\\n\\n    /\\*\\*\\n \\* the reserve's balance minus the upcoming flow is above the balance to be kept\\n \\* the flow can be added to the tapped amount\\n \\*/\\n    return tappedAmount;\\n}\\n```\\n\\nThat means that the amount that beneficiary can withdraw has just decreased, which should not be possible.

Impact:

Recommended mitigation:
Ensure that `tappedAmount` cannot be decreased once updated.
Vulnerability: Presale - contributionToken double cast and invalid comparison
Severity: medium

Description:
The Presale can be configured to accept `ETH` or a valid `ERC20` `token`. This `token` is stored as an `ERC20` contract type in the state variable `contributionToken`. It is then directly compared to constant `ETH` which is `address(0x0)` in various locations. Additionally, the `_transfer` function double casts the `token` to `ERC20` if the `contributionToken` is passed as an argument.\\n`contribute` - invalid comparison of contract type against `address(0x00)`. Even though this is accepted in solidity `<0.5.0` it is going to raise a compiler error with newer versions (>=0.5.0).\\n```\\nfunction contribute(address \\_contributor, uint256 \\_value) external payable nonReentrant auth(CONTRIBUTE\\_ROLE) {\\n    require(state() == State.Funding, ERROR\\_INVALID\\_STATE);\\n\\n    if (contributionToken == ETH) {\\n        require(msg.value == \\_value, ERROR\\_INVALID\\_CONTRIBUTE\\_VALUE);\\n    } else {\\n        require(msg.value == 0,      ERROR\\_INVALID\\_CONTRIBUTE\\_VALUE);\\n    }\\n```\\n\\n`_transfer` - double cast `token` to `ERC20` if it is the contribution `token`.\\n```\\nrequire(ERC20(\\_token).safeTransfer(\\_to, \\_amount), ERROR\\_TOKEN\\_TRANSFER\\_REVERTED);\\n```\\n

Impact:

Recommended mitigation:
`contributionToken` can either be `ETH` or a valid `ERC20` contract address. It is therefore recommended to store the token as an address type instead of the more precise contract type to resolve the double cast and the invalid contract type to address comparison or cast the `ERC20` type to `address()` before comparison.
Vulnerability: Fees are not returned for buy orders if a batch is canceled  Won't Fix
Severity: medium

Description:
Every trader pays fees on each buy order and transfers it directly to the `beneficiary`.\\n```\\nuint256 fee = \\_value.mul(buyFeePct).div(PCT\\_BASE);\\nuint256 value = \\_value.sub(fee);\\n\\n// collect fee and collateral\\nif (fee > 0) {\\n    \\_transfer(\\_buyer, beneficiary, \\_collateral, fee);\\n}\\n\\_transfer(\\_buyer, address(reserve), \\_collateral, value);\\n```\\n\\nIf the batch is canceled, fees are not returned to the traders because there is no access to the beneficiary account.\\nAdditionally, fees are returned to traders for all the sell orders if the batch is canceled.

Impact:

Recommended mitigation:
Consider transferring fees to a beneficiary only after the batch is over.
Vulnerability: Tap - Controller should not be updateable
Severity: medium

Description:
Similar to the issue 6.11, `Tap` allows updating the `Controller` contract it is using. The permission is currently not assigned in the `FundraisingMultisigTemplate` but might be used in custom deployments.\\n```\\n/\\*\\*\\n \\* @notice Update controller to `\\_controller`\\n \\* @param \\_controller The address of the new controller contract\\n\\*/\\nfunction updateController(IAragonFundraisingController \\_controller) external auth(UPDATE\\_CONTROLLER\\_ROLE) {\\n    require(isContract(\\_controller), ERROR\\_CONTRACT\\_IS\\_EOA);\\n\\n    \\_updateController(\\_controller);\\n}\\n```\\n

Impact:

Recommended mitigation:
To avoid inconsistencies, we suggest to remove this functionality and provide a guideline on how to safely upgrade components of the system.