msc-smart-contract-auditing/vulnerable-functions-base huggingface dataset:
Vulnerability: Emergency withdrawal code present
Severity: medium

Description:
Code and functionality for emergency stop and withdrawal is present in this code base.\\n```\\n    // ============================================\\n    // EMERGENCY WITHDRAWAL FUNCTIONS\\n    // Needs to be removed when final version deployed\\n    // ============================================\\n    function emergencyWithdraw(GlobalConfig globalConfig, address \\_token) public {\\n        address cToken = globalConfig.tokenInfoRegistry().getCToken(\\_token);\\n// rest of code\\n```\\n\\n```\\n    function emergencyWithdraw(address \\_token) external onlyEmergencyAddress {\\n        SavingLib.emergencyWithdraw(globalConfig, \\_token);\\n    }\\n```\\n\\n```\\n// rest of code\\n    address payable public constant EMERGENCY\\_ADDR = 0xc04158f7dB6F9c9fFbD5593236a1a3D69F92167c;\\n// rest of code\\n```\\n

Impact:

Recommended mitigation:
To remove the emergency code and fully test all the affected contracts.
Vulnerability: Naming inconsistency
Severity: low

Description:
There are some inconsistencies in the naming of some functions with what they do.\\n```\\n    function getCoinLength() public view returns (uint256 length) { //@audit-info coin vs token\\n        return tokens.length;\\n    }\\n```\\n

Impact:

Recommended mitigation:
Review the code for the naming inconsistencies.
Vulnerability: TokenFaucet refill can have an unexpected outcome
Severity: medium

Description:
The `TokenFaucet` contract can only disburse tokens to the users if it has enough balance. When the contract is running out of tokens, it stops dripping.\\n```\\nuint256 assetTotalSupply = asset.balanceOf(address(this));\\nuint256 availableTotalSupply = assetTotalSupply.sub(totalUnclaimed);\\nuint256 newSeconds = currentTimestamp.sub(lastDripTimestamp);\\nuint256 nextExchangeRateMantissa = exchangeRateMantissa;\\nuint256 newTokens;\\nuint256 measureTotalSupply = measure.totalSupply();\\n\\nif (measureTotalSupply > 0 && availableTotalSupply > 0 && newSeconds > 0) {\\n  newTokens = newSeconds.mul(dripRatePerSecond);\\n  if (newTokens > availableTotalSupply) {\\n    newTokens = availableTotalSupply;\\n  }\\n  uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0;\\n  nextExchangeRateMantissa = nextExchangeRateMantissa.add(indexDeltaMantissa);\\n\\n  emit Dripped(\\n    newTokens\\n  );\\n}\\n```\\n\\nThe owners of the faucet can decide to refill the contract so it can disburse tokens again. If there's been a lot of time since the faucet was drained, the `lastDripTimestamp` value can be far behind the `currentTimestamp`. In that case, the users can instantly withdraw some amount (up to all the balance) right after the refill.

Impact:

Recommended mitigation:
To avoid uncertainty, it's essential to call the `drip` function before the refill. If this call is made in a separate transaction, the owner should make sure that this transaction was successfully mined before sending tokens for the refill.
Vulnerability: Gas Optimization on transfers
Severity: low

Description:
In TokenFaucet, on every transfer `_captureNewTokensForUser` is called twice. This function does a few calculations and writes the latest UserState to the storage. However, if `lastExchangeRateMantissa == exchangeRateMantissa`, or in other words, two transfers happen in the same block, there are no changes in the newToken amounts, so there is an extra storage store with the same values.\\n`deltaExchangeRateMantissa` will be 0 in case two transfers ( no matter from or to) are in the same block for a user.\\n```\\n uint256 deltaExchangeRateMantissa = uint256(exchangeRateMantissa).sub(userState.lastExchangeRateMantissa);\\n    uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128();\\n    userStates[user] = UserState({\\n      lastExchangeRateMantissa: exchangeRateMantissa,\\n      balance: uint256(userState.balance).add(newTokens).toUint128()\\n    });\\n```\\n

Impact:

Recommended mitigation:
Return without storage update if `lastExchangeRateMantissa == exchangeRateMantissa`, or by another method if `deltaExchangeRateMantissa == 0`. This reduces the gas cost for active users (high number of transfers that might be in the same block)
Vulnerability: Handle transfer tokens where from == to
Severity: low

Description:
In TokenFaucet, when calling `beforeTokenTransfer` it should also be optimized when `to == from`. This is to prevent any possible issues with internal accounting and token drip calculations.\\n```\\n// rest of code\\n if (token == address(measure) && from != address(0)) {  //add && from != to\\n      drip();\\n// rest of code\\n```\\n

Impact:

Recommended mitigation:
As ERC20 standard, `from == to` can be allowed but check in `beforeTokenTransfer` that if `to == from`, then do not call `_captureNewTokensForUser(from);` again.
Vulnerability: Redundant/Duplicate checks
Severity: low

Description:
There are a few checks (require) in TokenFaucet that are redundant and/or checked twice.\\n```\\n    require(\\_dripRatePerSecond > 0, "TokenFaucet/dripRate-gt-zero");\\n    asset = \\_asset;\\n    measure = \\_measure;\\n    setDripRatePerSecond(\\_dripRatePerSecond);\\n```\\n\\n```\\n  function setDripRatePerSecond(uint256 \\_dripRatePerSecond) public onlyOwner {\\n    require(\\_dripRatePerSecond > 0, "TokenFaucet/dripRate-gt-zero");\\n```\\n\\n\\n```\\n  function drip() public returns (uint256) {\\n    uint256 currentTimestamp = \\_currentTime();\\n\\n    // this should only run once per block.\\n    if (lastDripTimestamp == uint32(currentTimestamp)) {\\n      return 0;\\n    }\\n// rest of code\\n    uint256 newSeconds = currentTimestamp.sub(lastDripTimestamp);\\n// rest of code\\n    if (measureTotalSupply > 0 && availableTotalSupply > 0 && newSeconds > 0) {\\n// rest of code\\n        uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; \\n```\\n

Impact:

Recommended mitigation:
Remove the redundant checks to reduce the code size and complexity.
Vulnerability: GenesisGroup.commit overwrites previously-committed values
Severity: high

Description:
`commit` allows anyone to `commit` purchased FGEN to a swap that will occur once the genesis group is launched. This commitment may be performed on behalf of other users, as long as the calling account has sufficient allowance:\\n```\\nfunction commit(address from, address to, uint amount) external override onlyGenesisPeriod {\\n burnFrom(from, amount);\\n\\n committedFGEN[to] = amount;\\n totalCommittedFGEN += amount;\\n\\n emit Commit(from, to, amount);\\n}\\n```\\n\\nThe `amount` stored in the recipient's `committedFGEN` balance overwrites any previously-committed value. Additionally, this also allows anyone to commit an `amount` of “0” to any account, deleting their commitment entirely.

Impact:

Recommended mitigation:
Ensure the committed amount is added to the existing commitment.
Vulnerability: UniswapIncentive overflow on pre-transfer hooks
Severity: high

Description:
Before a token transfer is performed, `Fei` performs some combination of mint/burn operations via UniswapIncentive.incentivize:\\n```\\nfunction incentivize(\\n address sender,\\n address receiver, \\n address operator,\\n uint amountIn\\n) external override onlyFei {\\n    updateOracle();\\n\\n if (isPair(sender)) {\\n  incentivizeBuy(receiver, amountIn);\\n }\\n\\n if (isPair(receiver)) {\\n        require(isSellAllowlisted(sender) || isSellAllowlisted(operator), "UniswapIncentive: Blocked Fei sender or operator");\\n  incentivizeSell(sender, amountIn);\\n }\\n}\\n```\\n\\nBoth `incentivizeBuy` and `incentivizeSell` calculate buy/sell incentives using overflow-prone math, then mint / burn from the target according to the results. This may have unintended consequences, like allowing a caller to mint tokens before transferring them, or burn tokens from their recipient.\\n`incentivizeBuy` calls `getBuyIncentive` to calculate the final minted value:\\n```\\nfunction incentivizeBuy(address target, uint amountIn) internal ifMinterSelf {\\n if (isExemptAddress(target)) {\\n  return;\\n }\\n\\n    (uint incentive, uint32 weight,\\n    Decimal.D256 memory initialDeviation,\\n    Decimal.D256 memory finalDeviation) = getBuyIncentive(amountIn);\\n\\n    updateTimeWeight(initialDeviation, finalDeviation, weight);\\n    if (incentive != 0) {\\n        fei().mint(target, incentive);        \\n    }\\n}\\n```\\n\\n`getBuyIncentive` calculates price deviations after casting `amount` to an `int256`, which may overflow:\\n```\\nfunction getBuyIncentive(uint amount) public view override returns(\\n    uint incentive,\\n    uint32 weight,\\n    Decimal.D256 memory initialDeviation,\\n    Decimal.D256 memory finalDeviation\\n) {\\n    (initialDeviation, finalDeviation) = getPriceDeviations(-1 \\* int256(amount));\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nThis was addressed in fei-protocol/fei-protocol-core#15.\\nEnsure casts in `getBuyIncentive` and `getSellPenalty` do not overflow.
Vulnerability: BondingCurve allows users to acquire FEI before launch
Severity: medium

Description:
`BondingCurve.allocate` allocates the protocol's held PCV, then calls `_incentivize`, which rewards the caller with FEI if a certain amount of time has passed:\\n```\\n/// @notice if window has passed, reward caller and reset window\\nfunction \\_incentivize() internal virtual {\\n    if (isTimeEnded()) {\\n        \\_initTimed(); // reset window\\n        fei().mint(msg.sender, incentiveAmount);\\n    }\\n}\\n```\\n\\n`allocate` can be called before genesis launch, as long as the contract holds some nonzero PCV. By force-sending the contract 1 wei, anyone can bypass the majority of checks and actions in `allocate`, and mint themselves FEI each time the timer expires.

Impact:

Recommended mitigation:
Prevent `allocate` from being called before genesis launch.
Vulnerability: Overflow/underflow protection
Severity: medium

Description:
Having overflow/underflow vulnerabilities is very common for smart contracts. It is usually mitigated by using `SafeMath` or using solidity version ^0.8 (after solidity 0.8 arithmetical operations already have default overflow/underflow protection).\\nIn this code, many arithmetical operations are used without the ‘safe' version. The reasoning behind it is that all the values are derived from the actual ETH values, so they can't overflow.\\nOn the other hand, some operations can't be checked for overflow/underflow without going much deeper into the codebase that is out of scope:\\n```\\nuint totalGenesisTribe = tribeBalance() - totalCommittedTribe;\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nThis was partially addressed in fei-protocol/fei-protocol-core#17 by using `SafeMath` for the specific example given in the description.\\nIn our opinion, it is still safer to have these operations in a safe mode. So we recommend using `SafeMath` or solidity version ^0.8 compiler.
Vulnerability: Unchecked return value for IWETH.transfer call
Severity: medium

Description:
In `EthUniswapPCVController`, there is a call to `IWETH.transfer` that does not check the return value:\\n```\\nweth.transfer(address(pair), amount);\\n```\\n\\nIt is usually good to add a require-statement that checks the return value or to use something like safeTransfer; unless one is sure the given token reverts in case of a failure.

Impact:

Recommended mitigation:
Consider adding a require-statement or using `safeTransfer`.
Vulnerability: GenesisGroup.emergencyExit remains functional after launch
Severity: medium

Description:
`emergencyExit` is intended as an escape mechanism for users in the event the genesis `launch` method fails or is frozen. `emergencyExit` becomes callable 3 days after `launch` is callable. These two methods are intended to be mutually-exclusive, but are not: either method remains callable after a successful call to the other.\\nThis may result in accounting edge cases. In particular, `emergencyExit` fails to decrease `totalCommittedFGEN` by the exiting user's commitment:\\n```\\nburnFrom(from, amountFGEN);\\ncommittedFGEN[from] = 0;\\n\\npayable(to).transfer(total);\\n```\\n\\nAs a result, calling launch after a user performs an exit will incorrectly calculate the amount of FEI to swap:\\n```\\nuint amountFei = feiBalance() \\* totalCommittedFGEN / (totalSupply() + totalCommittedFGEN);\\nif (amountFei != 0) {\\n totalCommittedTribe = ido.swapFei(amountFei);\\n}\\n```\\n

Impact:

Recommended mitigation:
Ensure `launch` cannot be called if `emergencyExit` has been called\\nEnsure `emergencyExit` cannot be called if `launch` has been called\\nIn `emergencyExit`, reduce `totalCommittedFGEN` by the exiting user's committed amount
Vulnerability: Unchecked return value for transferFrom calls
Severity: medium

Description:
There are two `transferFrom` calls that do not check the return value (some tokens signal failure by returning false):\\n```\\nstakedToken.transferFrom(from, address(this), amount);\\n```\\n\\n```\\nfei().transferFrom(msg.sender, address(pair), amountFei);\\n```\\n\\nIt is usually good to add a require-statement that checks the return value or to use something like safeTransferFrom; unless one is sure the given token reverts in case of a failure.

Impact:

Recommended mitigation:
Consider adding a require-statement or using `safeTransferFrom`.
Vulnerability: Pool: claiming to the pool itself causes accounting issues
Severity: low

Description:
```\\nfunction \\_claim(address from, address to) internal returns (uint256) {\\n    (uint256 amountReward, uint256 amountPool) = redeemableReward(from);\\n    require(amountPool != 0, "Pool: User has no redeemable pool tokens");\\n\\n    \\_burnFrom(from, amountPool);\\n    \\_incrementClaimed(amountReward);\\n\\n    rewardToken.transfer(to, amountReward);\\n    return amountReward;\\n}\\n```\\n\\nIf the destination address `to` is the pool itself, the pool will burn tokens and increment the amount of tokens claimed, then transfer the reward tokens `to` itself.

Impact:

Recommended mitigation:
Resolution\\nThis was addressed in fei-protocol/fei-protocol-core#57\\nPrevent claims from specifying the pool as a destination.
Vulnerability: Assertions that can fail
Severity: low

Description:
In `UniswapSingleEthRouter` there are two assert-statements that may fail:\\n```\\nassert(msg.sender == address(WETH)); // only accept ETH via fallback from the WETH contract\\n```\\n\\n```\\nassert(IWETH(WETH).transfer(address(PAIR), amountIn));\\n```\\n\\nSince they do some sort of input validation it might be good to replace them with require-statements. I would only use asserts for checks that should never fail and failure would constitute a bug in the code.

Impact:

Recommended mitigation:
Consider replacing the assert-statements with require-statements. An additional benefit is that this will not result in consuming all the gas in case of a violation.
Vulnerability: Simplify API of GenesisGroup.purchase
Severity: low

Description:
The API of `GenesisGroup.purchase` could be simplified by not including the `value` parameter that is required to be equivalent to msg.value:\\n```\\nrequire(msg.value == value, "GenesisGroup: value mismatch");\\n```\\n\\nUsing `msg.value` might make the API more explicit and avoid requiring `msg.value == value`. It can also save some gas due to fewer inputs and fewer checks.

Impact:

Recommended mitigation:
Consider dropping the `value` parameter and changing the code to use `msg.value` instead.
Vulnerability: The uniTransferFrom function can potentially be used with invalid params Unverified
Severity: medium

Description:
The system is using the `UniERC20` contract to incapsulate transfers of both ERC-20 tokens and ETH. This contract has `uniTransferFrom` function that can be used for any ERC-20 or ETH:\\n```\\nfunction uniTransferFrom(IERC20 token, address payable from, address to, uint256 amount) internal {\\n    if (amount > 0) {\\n        if (isETH(token)) {\\n            require(msg.value >= amount, "UniERC20: not enough value");\\n            if (msg.value > amount) {\\n                // Return remainder if exist\\n                from.transfer(msg.value.sub(amount));\\n            }\\n        } else {\\n            token.safeTransferFrom(from, to, amount);\\n        }\\n    }\\n}\\n```\\n\\nIn case if the function is called for the normal ERC-20 token, everything works as expected. The tokens are transferred `from` the `from` address `to` the `to` address. If the token is ETH - the transfer is expected `to` be `from` the `msg.sender` `to` `this` contract. Even if the `to` and `from` parameters are different.\\nThis issue's severity is not high because the function is always called with the proper parameters in the current codebase.

Impact:

Recommended mitigation:
Resolution\\nAccording to the client, this issue is addressed in 1inch-exchange/[email protected]d0ffb6f.\\n(This fix is as reported by the developer team, but has not been verified by Diligence).\\nMake sure that the `uniTransferFrom` function is always called with expected parameters.
Vulnerability: MooniswapGovernance - votingpower is not accurately reflected when minting pool tokens Unverified
Severity: medium

Description:
When a user provides liquidity to the pool, pool-tokens are minted. The minting event triggers the `_beforeTokenTransfer` callback in `MooniswapGovernance` which updates voting power reflecting the newly minted stake for the user.\\nThere seems to be a copy-paste error in the way `balanceTo` is determined that sets `balanceTo` to zero if new token were minted (from==address(0)). This means, that in a later call to `_updateOnTransfer` only the newly minted amount is considered when adjusting voting power.\\nIf tokens are newly minted `from==address(0)` and therefore `balanceTo -> 0`.\\n```\\nfunction \\_beforeTokenTransfer(address from, address to, uint256 amount) internal override {\\n    uint256 balanceFrom = (from != address(0)) ? balanceOf(from) : 0;\\n    uint256 balanceTo = (from != address(0)) ? balanceOf(to) : 0;\\n    uint256 newTotalSupply = totalSupply()\\n        .add(from == address(0) ? amount : 0)\\n        .sub(to == address(0) ? amount : 0);\\n\\n    ParamsHelper memory params = ParamsHelper({\\n        from: from,\\n        to: to,\\n        amount: amount,\\n        balanceFrom: balanceFrom,\\n        balanceTo: balanceTo,\\n        newTotalSupply: newTotalSupply\\n    });\\n```\\n\\nnow, `balanceTo` is zero which would adjust voting power to `amount` instead of the user's actual balance + the newly minted token.\\n```\\nif (params.to != address(0)) {\\n    votingData.updateBalance(params.to, voteTo, params.balanceTo, params.balanceTo.add(params.amount), params.newTotalSupply, defaultValue, emitEvent);\\n}\\n```\\n

Impact:

Recommended mitigation:
`balanceTo` should be zero when burning (to == address(0)) and `balanceOf(to)` when minting.\\ne.g. like this:\\n```\\nuint256 balanceTo = (to != address(0)) ? balanceOf(to) : 0;\\n```\\n
Vulnerability: The owner can borrow token0/token1 in the rescueFunds
Severity: low

Description:
If some random tokens/funds are accidentally transferred to the pool, the `owner` can call the `rescueFunds` function to withdraw any funds manually:\\n```\\nfunction rescueFunds(IERC20 token, uint256 amount) external nonReentrant onlyOwner {\\n    uint256 balance0 = token0.uniBalanceOf(address(this));\\n    uint256 balance1 = token1.uniBalanceOf(address(this));\\n\\n    token.uniTransfer(msg.sender, amount);\\n\\n    require(token0.uniBalanceOf(address(this)) >= balance0, "Mooniswap: access denied");\\n    require(token1.uniBalanceOf(address(this)) >= balance1, "Mooniswap: access denied");\\n    require(balanceOf(address(this)) >= \\_BASE\\_SUPPLY, "Mooniswap: access denied");\\n}\\n```\\n\\nThere's no restriction on which funds the `owner` can try to withdraw and which token to call. It's theoretically possible to transfer pool tokens and then return them to the contract (e.g. in the case of ERC-777). That action would be similar to a free flash loan.

Impact:

Recommended mitigation:
Explicitly check that the `token` is not equal to any of the pool tokens.
Vulnerability: UniswapFeature: Non-static call to ERC20.allowance()
Severity: low

Description:
In the case where a token is possibly “greedy” (consumes all gas on failure), `UniswapFeature` makes a call to the token's `allowance()` function to check whether the user has provided a token allowance to the protocol proxy or to the `AllowanceTarget`. This call is made using `call()`, potentially allowing state-changing operations to take place before control of the execution returns to `UniswapFeature`.\\n```\\n// `token.allowance()``\\nmstore(0xB00, ALLOWANCE\\_CALL\\_SELECTOR\\_32)\\nmstore(0xB04, caller())\\nmstore(0xB24, address())\\nlet success := call(gas(), token, 0, 0xB00, 0x44, 0xC00, 0x20)\\n```\\n

Impact:

Recommended mitigation:
Replace the `call()` with a `staticcall()`.
Vulnerability: UniswapFeature: Unchecked returndatasize in low-level external calls
Severity: low

Description:
`UniswapFeature` makes a number of external calls from low-level assembly code. Two of these calls rely on the `CALL` opcode to copy the returndata to memory without checking that the call returned the expected amount of data. Because the `CALL` opcode does not zero memory if the call returns less data than expected, this can lead to usage of dirty memory under the assumption that it is data returned from the most recent call.\\nCall to `UniswapV2Pair.getReserves()`\\n```\\n// Call pair.getReserves(), store the results at `0xC00`\\nmstore(0xB00, UNISWAP\\_PAIR\\_RESERVES\\_CALL\\_SELECTOR\\_32)\\nif iszero(staticcall(gas(), pair, 0xB00, 0x4, 0xC00, 0x40)) {\\n    bubbleRevert()\\n}\\n```\\n\\nCall to `ERC20.allowance()`\\n```\\n// Check if we have enough direct allowance by calling\\n// `token.allowance()``\\nmstore(0xB00, ALLOWANCE\\_CALL\\_SELECTOR\\_32)\\nmstore(0xB04, caller())\\nmstore(0xB24, address())\\nlet success := call(gas(), token, 0, 0xB00, 0x44, 0xC00, 0x20)\\n```\\n

Impact:

Recommended mitigation:
Instead of providing a memory range for `call()` to write returndata to, explicitly check `returndatasize()` after the call is made and then copy the data into memory using `returndatacopy()`.\\n```\\nif lt(returndatasize(), EXPECTED\\_SIZE) {\\n    revert(0, 0) \\n}\\nreturndatacopy(0xC00, 0x00, EXPECTED\\_SIZE)\\n```\\n