msc-smart-contract-auditing/vulnerable-functions-base huggingface dataset:
Vulnerability: LibMath - roundHalfUp returns unfinished result
Severity: low

Description:
The method `LibMathSigned.roundHalfUp(int `x`, int y)` returns the value `x` rounded up to the base `y`. The method suggests that the result is the rounded value while that's not actually true. The result for a positive `x` is `x` + base/2 and `x` - base/2 for negative values. The rounding is not yet finished as this would require a final division by base `y` to manifest the rounding.\\nIt is assumed that the final rounding step is not executed for performance reasons. However, this might easily introduce errors when the caller assumes the result is rounded for base while it is not.\\n`roundHalfUp(-4700, 1000) = -4700` instead of `5000`\\n`roundHalfUp(4700, 1000) = 4700` instead of `5000`\\n```\\n// ROUND\\_HALF\\_UP rule helper. 0.5 ≈ 1, 0.4 ≈ 0, -0.5 ≈ -1, -0.4 ≈ 0\\nfunction roundHalfUp(int256 x, int256 y) internal pure returns (int256) {\\n    require(y > 0, "roundHalfUp only supports y > 0");\\n    if (x >= 0) {\\n        return add(x, y / 2);\\n    }\\n    return sub(x, y / 2);\\n}\\n```\\n

Impact:

Recommended mitigation:
We have verified the current code-base and the callers for `roundHalfUp` are correctly finishing the rounding step. However, it is recommended to finish the rounding within the method or document this behavior to prevent errors caused by code that falsely assumes that the returned value finished rounding.
Vulnerability: LibMath/LibOrder - unused named return value
Severity: low

Description:
The following methods declare a named return value but explicitly return a value instead. The named return value is not used.\\n`LibMathSigned.min()`\\n`LibMathSigned.max()`\\n`LibMathUnsigned.min()`\\n`LibMathUnsigned.max()`\\n`LibOrder.getOrderHash()`\\n`LibOrder.hashOrder()`\\n```\\nfunction min(int256 x, int256 y) internal pure returns (int256 z) {\\n    return x <= y ? x : y;\\n}\\n\\nfunction max(int256 x, int256 y) internal pure returns (int256 z) {\\n    return x >= y ? x : y;\\n}\\n```\\n\\n```\\nfunction min(uint256 x, uint256 y) internal pure returns (uint256 z) {\\n    return x <= y ? x : y;\\n}\\n\\nfunction max(uint256 x, uint256 y) internal pure returns (uint256 z) {\\n    return x >= y ? x : y;\\n}\\n```\\n\\n```\\nfunction getOrderHash(Order memory order) internal pure returns (bytes32 orderHash) {\\n    orderHash = LibEIP712.hashEIP712Message(hashOrder(order));\\n    return orderHash;\\n}\\n```\\n\\n```\\nfunction hashOrder(Order memory order) internal pure returns (bytes32 result) {\\n    bytes32 orderType = EIP712\\_ORDER\\_TYPE;\\n    // solium-disable-next-line security/no-inline-assembly\\n    assembly {\\n        let start := sub(order, 32)\\n        let tmp := mload(start)\\n        mstore(start, orderType)\\n        result := keccak256(start, 224)\\n        mstore(start, tmp)\\n    }\\n    return result;\\n}\\n```\\n

Impact:

Recommended mitigation:
Remove the named return value and explicitly return the value.
Vulnerability: Commented code exists in BMath
Severity: low

Description:
```\\nuint tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn);\\n\\n// uint newPoolSupply = (ratioTi ^ weightTi) \\* poolSupply;\\nuint poolRatio = bpow(tokenInRatio, normalizedWeight);\\n```\\n\\n```\\nuint normalizedWeight = bdiv(tokenWeightOut, totalWeight);\\n// charge exit fee on the pool token side\\n// pAiAfterExitFee = pAi\\*(1-exitFee)\\nuint poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BONE, EXIT\\_FEE));\\n```\\n\\nAnd many more examples.

Impact:

Recommended mitigation:
Remove the commented code, or address them properly. If the code is related to exit fee, which is considered to be 0 in this version, this style should be persistent in other contracts as well.
Vulnerability: Max weight requirement in rebind is inaccurate
Severity: low

Description:
`BPool.rebind` enforces `MIN_WEIGHT` and `MAX_WEIGHT` bounds on the passed-in `denorm` value:\\n```\\nfunction rebind(address token, uint balance, uint denorm)\\n    public\\n    \\_logs\\_\\n    \\_lock\\_\\n{\\n\\n    require(msg.sender == \\_controller, "ERR\\_NOT\\_CONTROLLER");\\n    require(\\_records[token].bound, "ERR\\_NOT\\_BOUND");\\n    require(!\\_finalized, "ERR\\_IS\\_FINALIZED");\\n\\n    require(denorm >= MIN\\_WEIGHT, "ERR\\_MIN\\_WEIGHT");\\n    require(denorm <= MAX\\_WEIGHT, "ERR\\_MAX\\_WEIGHT");\\n    require(balance >= MIN\\_BALANCE, "ERR\\_MIN\\_BALANCE");\\n```\\n\\n`MIN_WEIGHT` is `1 BONE`, and `MAX_WEIGHT` is `50 BONE`.\\nThough a token weight of `50 BONE` may make sense in a single-token system, `BPool` is intended to be used with two to eight tokens. The sum of the weights of all tokens must not be greater than `50 BONE`.\\nThis implies that a weight of `50 BONE` for any single token is incorrect, given that at least one other token must be present.

Impact:

Recommended mitigation:
`MAX_WEIGHT` for any single token should be `MAX_WEIGHT` - MIN_WEIGHT, or `49 BONE`.
Vulnerability: Test code present in the code base
Severity: medium

Description:
Test code are present in the code base. This is mainly a reminder to fix those before production.\\n`rescuerAddress` and `freezerAddress` are not even in the function arguments.\\n```\\nwhitelistingAddress = \\_whitelistingAddress;\\nprojectAddress = \\_projectAddress;\\nfreezerAddress = \\_projectAddress; // TODO change, here only for testing\\nrescuerAddress = \\_projectAddress; // TODO change, here only for testing\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nFixed in lukso-network/[email protected]edb880c.\\nMake sure all the variable assignments are ready for production before deployment to production.
Vulnerability: frozenPeriod is subtracted twice for calculating the current price
Severity: medium

Description:
If the contract had been frozen, the current stage price will calculate the price by subtracting the `frozenPeriod` twice and result in wrong calculation.\\n`getCurrentBlockNumber()` subtracts `frozenPeriod` once, and then `getStageAtBlock()` will also subtract the same number again.\\n```\\nfunction getCurrentStage() public view returns (uint8) {\\n    return getStageAtBlock(getCurrentBlockNumber());\\n}\\n```\\n\\n```\\nfunction getCurrentBlockNumber() public view returns (uint256) {\\n    return uint256(block.number)\\n    .sub(frozenPeriod); // make sure we deduct any frozenPeriod from calculations\\n}\\n```\\n\\n```\\nfunction getStageAtBlock(uint256 \\_blockNumber) public view returns (uint8) {\\n\\n    uint256 blockNumber = \\_blockNumber.sub(frozenPeriod); // adjust the block by the frozen period\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nFound in parallel to the audit team and has been mitigated in lukso-network/[email protected]ebc4bce . The issue was further simplified by adding `getCurrentEffectiveBlockNumber()` in lukso-network/[email protected]e4c9ed5 to remove ambiguity when calculating current block number.\\nMake sure `frozenPeriod` calculation is done correctly. It could be solved by renaming `getCurrentBlockNumber()` to reflect the calculation done inside the function.\\ne.g. :\\n`getCurrentBlockNumber()` : gets current block number\\n`getCurrentEffectiveBlockNumber()` : calculates the effective block number deducting `frozenPeriod`
Vulnerability: Gold order size should be limited
Severity: high

Description:
When a user submits an order to buy gold cards, it's possible to buy a huge amount of cards. `_commit` function uses less gas than `mineGolds`, which means that the user can successfully commit to buying this amount of cards and when it's time to collect them, `mineGolds` function may run out of gas because it iterates over all card IDs and mints them:\\n```\\n// Mint gold cards\\nskyweaverAssets.batchMint(\\_order.cardRecipient, \\_ids, amounts, "");\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nAddressed in horizon-games/SkyWeaver-contracts#9 by adding a limit for cold cards amount in one order.\\nLimit a maximum gold card amount in one order.
Vulnerability: Price and refund changes may cause failures
Severity: high

Description:
Price and refund for gold cards are used in 3 different places: commit, mint, refund.\\nWeave tokens spent during the commit phase\\n```\\nfunction \\_commit(uint256 \\_weaveAmount, GoldOrder memory \\_order)\\n  internal\\n{\\n  // Check if weave sent is sufficient for order\\n  uint256 total\\_cost = \\_order.cardAmount.mul(goldPrice).add(\\_order.feeAmount);\\n  uint256 refund\\_amount = \\_weaveAmount.sub(total\\_cost); // Will throw if insufficient amount received\\n```\\n\\nbut they are burned `rngDelay` blocks after\\n```\\n// Burn the non-refundable weave\\nuint256 weave\\_to\\_burn = (\\_order.cardAmount.mul(goldPrice)).sub(\\_order.cardAmount.mul(goldRefund));\\nweaveContract.burn(weaveID, weave\\_to\\_burn);\\n```\\n\\nIf the price is increased between these transactions, mining cards may fail because it should burn more `weave` tokens than there are tokens in the smart contract. Even if there are enough tokens during this particular transaction, someone may fail to melt a gold card later.\\nIf the price is decreased, some `weave` tokens will be stuck in the contract forever without being burned.

Impact:

Recommended mitigation:
Store `goldPrice` and `goldRefund` in `GoldOrder`.
Vulnerability: Re-entrancy attack allows to buy EternalHeroes cheaper
Severity: high

Description:
When buying eternal heroes in `_buy` function of `EternalHeroesFactory` contract, a buyer can do re-entracy before items are minted.\\n```\\nuint256 refundAmount = \\_arcAmount.sub(total\\_cost);\\nif (refundAmount > 0) {\\n  arcadeumCoin.safeTransferFrom(address(this), \\_recipient, arcadeumCoinID, refundAmount, "");\\n}\\n\\n// Mint tokens to recipient\\nfactoryManager.batchMint(\\_recipient, \\_ids, amounts\\_to\\_mint, "");\\n```\\n\\nSince price should increase after every `N` items are minted, it's possible to buy more items with the old price.

Impact:

Recommended mitigation:
Add re-entrancy protection or mint items before sending the refund.
Vulnerability: Supply limitation misbehaviors
Severity: medium

Description:
In `SWSupplyManager` contract, the `owner` can limit supply for any token ID by setting maxSupply:\\n```\\nfunction setMaxSupplies(uint256[] calldata \\_ids, uint256[] calldata \\_newMaxSupplies) external onlyOwner() {\\n  require(\\_ids.length == \\_newMaxSupplies.length, "SWSupplyManager#setMaxSupply: INVALID\\_ARRAYS\\_LENGTH");\\n\\n  // Can only \\*decrease\\* a max supply\\n  // Can't set max supply back to 0\\n  for (uint256 i = 0; i < \\_ids.length; i++ ) {\\n    if (maxSupply[\\_ids[i]] > 0) {\\n      require(\\n        0 < \\_newMaxSupplies[i] && \\_newMaxSupplies[i] < maxSupply[\\_ids[i]],\\n        "SWSupplyManager#setMaxSupply: INVALID\\_NEW\\_MAX\\_SUPPLY"\\n      );\\n    }\\n    maxSupply[\\_ids[i]] = \\_newMaxSupplies[i];\\n  }\\n\\n  emit MaxSuppliesChanged(\\_ids, \\_newMaxSupplies);\\n}\\n```\\n\\nThe problem is that you can set `maxSupply` that is lower than `currentSupply`, which would be an unexpected state to have.\\nAlso, if some tokens are burned, their `currentSupply` is not decreasing:\\n```\\nfunction burn(\\n  uint256 \\_id,\\n  uint256 \\_amount)\\n  external\\n{\\n  \\_burn(msg.sender, \\_id, \\_amount);\\n}\\n```\\n\\nThis unexpected behaviour may lead to burning all of the tokens without being able to mint more.

Impact:

Recommended mitigation:
Properly track `currentSupply` by modifying it in `burn` function. Consider having a following restriction `require(_newMaxSupplies[i] > currentSupply[_ids[i]])` in `setMaxSupplies` function.
Vulnerability: importScore() in IexecMaintenanceDelegate can be used to wrongfully reset worker scores  Acknowledged
Severity: medium

Description:
The import of worker scores from the previous PoCo system deployed on chain is made to be asynchronous. And, even though the pull pattern usually makes a system much more resilient, in this case, it opens up the possibility for an attack that undermines the trust-based game-theoretical balance the PoCo system relies on. As can be seen in the following function:\\n```\\nfunction importScore(address \\_worker)\\nexternal override\\n{\\n require(!m\\_v3\\_scoreImported[\\_worker], "score-already-imported");\\n m\\_workerScores[\\_worker] = m\\_workerScores[\\_worker].max(m\\_v3\\_iexecHub.viewScore(\\_worker));\\n m\\_v3\\_scoreImported[\\_worker] = true;\\n}\\n```\\n\\nA motivated attacker could attack the system providing bogus results for computation tasks therefore reducing his own reputation (mirrored by the low worker score that would follow).\\nAfter the fact, the attacker could reset its score to the previous high value attained in the previously deployed PoCo system (v3) and undo all the wrongdoings he had done at no reputational cost.

Impact:

Recommended mitigation:
Resolution\\nUpdate from the iExec team:\\nIn order to perform this attack, one would first have to gain reputation on the new version, and lose it. They would then be able to restore its score from the old version.\\nWe feel the risk is acceptable for a few reasons:\\nIt can only be done once per worker\\nConsidering the score dynamics discussed in the “Trust in the PoCo” document, it is more interesting for a worker to import its reputation in the beginning rather then creating a new one, since bad contributions only remove part of the reputation\\nOnly a handful of workers have reputation in the old system (180), and their score is low (average 7, max 22)\\nWe might force the import all 180 workers with reputation >0. A script to identify the relevant addresses is already available.\\nCheck that each worker interacting with the PoCo system has already imported his score. Otherwise import it synchronously with a call at the time of their first interaction.
Vulnerability: Domain separator in iExecMaintenanceDelegate has a wrong version field  Acknowledged
Severity: medium

Description:
The domain separator used to comply with the EIP712 standard in `iExecMaintenanceDelegate` has a wrong version field.\\n```\\nfunction \\_domain()\\ninternal view returns (IexecLibOrders\\_v5.EIP712Domain memory)\\n{\\n return IexecLibOrders\\_v5.EIP712Domain({\\n  name:              "iExecODB"\\n , version:           "3.0-alpha"\\n , chainId:           \\_chainId()\\n , verifyingContract: address(this)\\n });\\n}\\n```\\n\\nIn the above snippet we can see the code is still using the version field from an old version of the PoCo protocol, `"3.0-alpha"`.

Impact:

Recommended mitigation:
Resolution\\nIssue was fixed in iExecBlockchainComputing/[email protected]ebee370\\nChange the version field to: `"5.0-alpha"`
Vulnerability: The updateContract() method in ERC1538UpdateDelegate is incorrectly implemented
Severity: low

Description:
The `updateContract()` method in `ERC1538UpdateDelegate` does not behave as intended for some specific streams of bytes (meant to be parsed as function signatures).\\nThe mentioned function takes as input, among other things, a `string` (which is, canonically, a dynamically-sized `bytes` array) and tries to parse it as a conjunction of function signatures.\\nAs is evident in:\\n```\\nif (char == 0x3B) // 0x3B = ';'\\n```\\n\\nInside the function, `;` is being used as a “reserved” character, serving as a delimiter between each function signature.\\nHowever, if two semicolons are used in succession, the second one will not be checked and will be made part of the function signature being sent into the `_setFunc()` method.\\nExample of faulty input\\n`someFunc;;someOtherFuncWithSemiColon;`

Impact:

Recommended mitigation:
Resolution\\nIssue was fixed in iExecBlockchainComputing/[email protected]e6be083\\nReplace the line that increases the `pos` counter at the end of the function:\\n```\\nstart = ++pos;\\n```\\n\\nWIth this line of code:\\n`start = pos + 1;`
Vulnerability: TokenStaking.recoverStake allows instant stake undelegation
Severity: high

Description:
`TokenStaking.recoverStake` is used to recover stake that has been designated to be undelegated. It contains a single check to ensure that the undelegation period has passed:\\n```\\nfunction recoverStake(address \\_operator) public {\\n    uint256 operatorParams = operators[\\_operator].packedParams;\\n    require(\\n        block.number > operatorParams.getUndelegationBlock().add(undelegationPeriod),\\n        "Can not recover stake before undelegation period is over."\\n    );\\n```\\n\\nHowever, if an undelegation period is never set, this will always return true, allowing any operator to instantly undelegate stake at any time.

Impact:

Recommended mitigation:
Require that the undelegation period is nonzero before allowing an operator to recover stake.
Vulnerability: tbtc - No access control in TBTCSystem.requestNewKeep
Severity: high

Description:
`TBTCSystem.requestNewKeep` is used by each new `Deposit` contract on creation. It calls `BondedECDSAKeepFactory.openKeep`, which sets the `Deposit` contract as the “owner,” a permissioned role within the created keep. `openKeep` also automatically allocates bonds from members registered to the application. The “application” from which member bonds are allocated is the tbtc system itself.\\nBecause `requestNewKeep` has no access controls, anyone can request that a keep be opened with `msg.sender` as the “owner,” and arbitrary signing threshold values:\\n```\\n/// @notice Request a new keep opening.\\n/// @param \\_m Minimum number of honest keep members required to sign.\\n/// @param \\_n Number of members in the keep.\\n/// @return Address of a new keep.\\nfunction requestNewKeep(uint256 \\_m, uint256 \\_n, uint256 \\_bond)\\n    external\\n    payable\\n    returns (address)\\n{\\n    IBondedECDSAKeepVendor \\_keepVendor = IBondedECDSAKeepVendor(keepVendor);\\n    IBondedECDSAKeepFactory \\_keepFactory = IBondedECDSAKeepFactory(\\_keepVendor.selectFactory());\\n    return \\_keepFactory.openKeep.value(msg.value)(\\_n, \\_m, msg.sender, \\_bond);\\n}\\n```\\n\\nGiven that the owner of a keep is able to seize signer bonds, close the keep, and more, having control of this role could be detrimental to group members.

Impact:

Recommended mitigation:
Resolution\\nIssue addressed in keep-network/tbtc#514. Each call to `requestNewKeep` makes a check that `uint(msg.sender)` is an existing `TBTCDepositToken`. Because these tokens are only minted in `DepositFactory`, `msg.sender` would have to be one of the cloned deposit contracts.\\nAdd access control to `requestNewKeep`, so that it can only be called as a part of the `Deposit` creation and initialization process.
Vulnerability: keep-core - reportRelayEntryTimeout creates an incentive for nodes to race for rewards potentially wasting gas and it creates an opportunity for front-running
Severity: high

Description:
The incentive on `reportRelayEntryTimeout` for being rewarded with 5% of the seized amount creates an incentive to call the method but might also kick off a race for front-running this call. This method is being called from the keep node which is unlikely to adjust the gasPrice and might always lose the race against a front-running bot collecting rewards for all timeouts and fraud proofs (issue 5.7)\\n```\\n/\\*\\*\\n \\* @dev Function used to inform about the fact the currently ongoing\\n \\* new relay entry generation operation timed out. As a result, the group\\n \\* which was supposed to produce a new relay entry is immediately\\n \\* terminated and a new group is selected to produce a new relay entry.\\n \\* All members of the group are punished by seizing minimum stake of\\n \\* their tokens. The submitter of the transaction is rewarded with a\\n \\* tattletale reward which is limited to min(1, 20 / group\\_size) of the\\n \\* maximum tattletale reward.\\n \\*/\\nfunction reportRelayEntryTimeout() public {\\n    require(hasEntryTimedOut(), "Entry did not time out");\\n    groups.reportRelayEntryTimeout(signingRequest.groupIndex, groupSize, minimumStake);\\n\\n    // We could terminate the last active group. If that's the case,\\n    // do not try to execute signing again because there is no group\\n    // which can handle it.\\n    if (numberOfGroups() > 0) {\\n        signRelayEntry(\\n            signingRequest.relayRequestId,\\n            signingRequest.previousEntry,\\n            signingRequest.serviceContract,\\n            signingRequest.entryVerificationAndProfitFee,\\n            signingRequest.callbackFee\\n        );\\n    }\\n}\\n```\\n

Impact:

Recommended mitigation:
Make sure that `reportRelayEntryTimeout` throws as early as possible if the group was previously terminated (isGroupTerminated) to avoid that keep-nodes spend gas on a call that will fail. Depending on the reward for calling out the timeout this might create a front-running opportunity that cannot be resolved.
Vulnerability: keep-core - reportUnauthorizedSigning fraud proof is not bound to reporter and can be front-run
Severity: high

Description:
An attacker can monitor `reportUnauthorizedSigning()` for fraud reports and attempt to front-run the original call in an effort to be the first one reporting the fraud and be rewarded 5% of the total seized amount.\\n```\\n/\\*\\*\\n \\* @dev Reports unauthorized signing for the provided group. Must provide\\n \\* a valid signature of the group address as a message. Successful signature\\n \\* verification means the private key has been leaked and all group members\\n \\* should be punished by seizing their tokens. The submitter of this proof is\\n \\* rewarded with 5% of the total seized amount scaled by the reward adjustment\\n \\* parameter and the rest 95% is burned.\\n \\*/\\nfunction reportUnauthorizedSigning(\\n    uint256 groupIndex,\\n    bytes memory signedGroupPubKey\\n) public {\\n    groups.reportUnauthorizedSigning(groupIndex, signedGroupPubKey, minimumStake);\\n}\\n```\\n

Impact:

Recommended mitigation:
Require the reporter to include `msg.sender` in the signature proving the fraud or implement a two-step commit/reveal scheme to counter front-running opportunities by forcing a reporter to secretly commit the fraud parameters in one block and reveal them in another.