msc-smart-contract-auditing/vulnerable-functions-base huggingface dataset:
Vulnerability: Exchange - insufficient input validation in matchOrders  Pending
Severity: medium

Description:
`matchOrders` does not check that that the sender has provided the same number of `amounts` as `makerOrderParams`. When fewer `amounts` exist than `makerOrderParams`, the method will revert because of an out-of-bounds array access. When fewer `makerOrderParams` exist than `amounts`, the method will succeed, and the additional values in `amounts` will be ignored.\\nAdditionally, the method allows the sender to provide no `makerOrderParams` at all, resulting in no state changes.\\n`matchOrders` also does not reject trades with an amount set to zero. Such orders should be rejected because they do not comply with the minimum `tradingLotSize` configured for the system. As a side-effect, events may be emitted for zero-amount trades and unexpected state changes may occur.\\n```\\nfunction matchOrders(\\n    LibOrder.OrderParam memory takerOrderParam,\\n    LibOrder.OrderParam[] memory makerOrderParams,\\n    address \\_perpetual,\\n    uint256[] memory amounts\\n) public {\\n```\\n\\n```\\nfunction matchOrderWithAMM(LibOrder.OrderParam memory takerOrderParam, address \\_perpetual, uint256 amount) public {\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nThis issue was addressed by following the recommendation to verify that `amounts.length > 0 && makerOrderParams.length == amounts.length`. However, the code does not abort if one of the `amounts` is zero which should never happen and therefore raise an exception due to it likely being an erroneous call. Additionally, the method now enforces that only a broker can interact with the interface.\\nRequire `makerOrderParams.length > 0 && amounts.length == makerOrderParams.length`\\nRequire that `amount` or any of the `amounts[i]` provided to `matchOrders` is `>=tradingLotSize`.
Vulnerability: AMM - Liquidity provider may lose up to lotSize when removing liquidity  Acknowledged
Severity: medium

Description:
When removing liquidity, the amount of collateral received is calculated from the `shareAmount` (ShareToken) of the liquidity provider. The liquidity removal process registers a trade on the amount, with the liquidity provider and `AMM` taking opposite sides. Because trading only accepts multiple of the `lotSize`, the leftover is discarded. The amount discarded may be up to `lotSize - 1`.\\nThe expectation is that this value should not be too high, but as `lotSize` can be set to arbitrary values by an admin, it is possible that this step discards significant value. Additionally, see issue 6.6 for how this can be exploited by an admin.\\nNote that similar behavior is present in `Perpetual.liquidateFrom`, where the `liquidatableAmount` calculated undergoes a similar modulo operation:\\n```\\nuint256 liquidatableAmount = totalPositionSize.sub(totalPositionSize.mod(governance.lotSize));\\nliquidationAmount = liquidationAmount.ceil(governance.lotSize).min(maxAmount).min(liquidatableAmount);\\n```\\n\\n`lotSize` can arbitrarily be set up to `pos_int256_max` as long as `tradingLotSize % `lotSize` == 0`\\n```\\n} else if (key == "lotSize") {\\n    require(\\n        governance.tradingLotSize == 0 || governance.tradingLotSize.mod(value.toUint256()) == 0,\\n        "require tls % ls == 0"\\n    );\\n    governance.lotSize = value.toUint256();\\n} else if (key == "tradingLotSize") {\\n    require(governance.lotSize == 0 || value.toUint256().mod(governance.lotSize) == 0, "require tls % ls == 0");\\n    governance.tradingLotSize = value.toUint256();\\n```\\n\\n`amount` is derived from `shareAmount` rounded down to the next multiple of the `lotSize`. The leftover is discarded.\\n```\\nuint256 amount = shareAmount.wmul(oldPoolPositionSize).wdiv(shareToken.totalSupply());\\namount = amount.sub(amount.mod(perpetualProxy.lotSize()));\\n\\nperpetualProxy.transferBalanceOut(trader, price.wmul(amount).mul(2));\\nburnShareTokenFrom(trader, shareAmount);\\nuint256 opened = perpetualProxy.trade(trader, LibTypes.Side.LONG, price, amount);\\n```\\n

Impact:

Recommended mitigation:
Ensure that documentation makes users aware of the fact that they may lose up to `lotsize-1` in value.\\nAlternatively, track accrued value and permit trades on values that exceed `lotSize`. Note that this may add significant complexity.\\nEnsure that similar system behavior, like the `liquidatableAmount` calculated in `Perpetual.liquidateFrom`, is also documented and communicated clearly to users.
Vulnerability: Oracle - Unchecked oracle response timestamp and integer over/underflow
Severity: medium

Description:
The external Chainlink oracle, which provides index price information to the system, introduces risk inherent to any dependency on third-party data sources. For example, the oracle could fall behind or otherwise fail to be maintained, resulting in outdated data being fed to the index price calculations of the AMM. Oracle reliance has historically resulted in crippled on-chain systems, and complications that lead to these outcomes can arise from things as simple as network congestion.\\nEnsuring that unexpected oracle return values are properly handled will reduce reliance on off-chain components and increase the resiliency of the smart contract system that depends on them.\\nThe `ChainlinkAdapter` and `InversedChainlinkAdapter` take the oracle's (int256) `latestAnswer` and convert the result using `chainlinkDecimalsAdapter`. This arithmetic operation can underflow/overflow if the Oracle provides a large enough answer:\\n```\\nint256 public constant chainlinkDecimalsAdapter = 10\\*\\*10;\\n\\nconstructor(address \\_feeder) public {\\n    feeder = IChainlinkFeeder(\\_feeder);\\n}\\n\\nfunction price() public view returns (uint256 newPrice, uint256 timestamp) {\\n    newPrice = (feeder.latestAnswer() \\* chainlinkDecimalsAdapter).toUint256();\\n    timestamp = feeder.latestTimestamp();\\n}\\n```\\n\\n```\\nint256 public constant chainlinkDecimalsAdapter = 10\\*\\*10;\\n\\nconstructor(address \\_feeder) public {\\n    feeder = IChainlinkFeeder(\\_feeder);\\n}\\n\\nfunction price() public view returns (uint256 newPrice, uint256 timestamp) {\\n    newPrice = ONE.wdiv(feeder.latestAnswer() \\* chainlinkDecimalsAdapter).toUint256();\\n    timestamp = feeder.latestTimestamp();\\n}\\n```\\n\\nThe oracle provides a timestamp for the `latestAnswer` that is not validated and may lead to old oracle timestamps being accepted (e.g. caused by congestion on the blockchain or a directed censorship attack).\\n```\\n    timestamp = feeder.latestTimestamp();\\n}\\n```\\n

Impact:

Recommended mitigation:
Use `SafeMath` for mathematical computations\\nVerify `latestAnswer` is within valid bounds (!=0)\\nVerify `latestTimestamp` is within accepted bounds (not in the future, was updated within a reasonable amount of time)\\nDeduplicate code by combining both Adapters into one as the only difference is that the `InversedChainlinkAdapter` returns `ONE.wdiv(price)`.
Vulnerability: Perpetual - Administrators can put the system into emergency mode indefinitely  Pending
Severity: medium

Description:
There is no limitation on how long an administrator can put the `Perpetual` contract into emergency mode. Users cannot trade or withdraw funds in emergency mode and are effectively locked out until the admin chooses to put the contract in `SETTLED` mode.\\n```\\nfunction beginGlobalSettlement(uint256 price) public onlyWhitelistAdmin {\\n    require(status != LibTypes.Status.SETTLED, "already settled");\\n    settlementPrice = price;\\n    status = LibTypes.Status.SETTLING;\\n    emit BeginGlobalSettlement(price);\\n}\\n```\\n\\n```\\nfunction endGlobalSettlement() public onlyWhitelistAdmin {\\n    require(status == LibTypes.Status.SETTLING, "wrong perpetual status");\\n\\n    address guy = address(amm.perpetualProxy());\\n    settleFor(guy);\\n    status = LibTypes.Status.SETTLED;\\n\\n    emit EndGlobalSettlement();\\n}\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nThe client provided the following statement addressing the issue:\\nIt should be solved by voting. Moreover, we add two roles who is able to disable withdrawing /pause the system.\\nThe duration of the emergency phase is still unrestricted.\\nSet a time-lock when entering emergency mode that allows anyone to set the system to `SETTLED` after a fixed amount of time.
Vulnerability: Signed data may be usable cross-chain
Severity: medium

Description:
Signed order data may be re-usable cross-chain as the chain-id is not explicitly part of the signed data.\\nIt is also recommended to further harden the signature verification and validate that `v` and `s` are within expected bounds. `ecrecover()` returns `0x0` to indicate an error condition, therefore, a `signerAddress` or `recovered` address of `0x0` should explicitly be disallowed.\\nThe signed order data currently includes the EIP712 Domain Name `Mai Protocol` and the following information:\\n```\\nstruct Order {\\n    address trader;\\n    address broker;\\n    address perpetual;\\n    uint256 amount;\\n    uint256 price;\\n    /\\*\\*\\n \\* Data contains the following values packed into 32 bytes\\n \\* ╔════════════════════╤═══════════════════════════════════════════════════════════╗\\n \\* ║ │ length(bytes) desc ║\\n \\* ╟────────────────────┼───────────────────────────────────────────────────────────╢\\n \\* ║ version │ 1 order version ║\\n \\* ║ side │ 1 0: buy (long), 1: sell (short) ║\\n \\* ║ isMarketOrder │ 1 0: limitOrder, 1: marketOrder ║\\n \\* ║ expiredAt │ 5 order expiration time in seconds ║\\n \\* ║ asMakerFeeRate │ 2 maker fee rate (base 100,000) ║\\n \\* ║ asTakerFeeRate │ 2 taker fee rate (base 100,000) ║\\n \\* ║ (d) makerRebateRate│ 2 rebate rate for maker (base 100) ║\\n \\* ║ salt │ 8 salt ║\\n \\* ║ isMakerOnly │ 1 is maker only ║\\n \\* ║ isInversed │ 1 is inversed contract ║\\n \\* ║ │ 8 reserved ║\\n \\* ╚════════════════════╧═══════════════════════════════════════════════════════════╝\\n \\*/\\n    bytes32 data;\\n}\\n```\\n\\nSignature verification:\\n```\\nfunction isValidSignature(OrderSignature memory signature, bytes32 hash, address signerAddress)\\n    internal\\n    pure\\n    returns (bool)\\n{\\n    uint8 method = uint8(signature.config[1]);\\n    address recovered;\\n    uint8 v = uint8(signature.config[0]);\\n\\n    if (method == uint8(SignatureMethod.ETH\\_SIGN)) {\\n        recovered = ecrecover(\\n            keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\\n32", hash)),\\n            v,\\n            signature.r,\\n            signature.s\\n        );\\n    } else if (method == uint8(SignatureMethod.EIP712)) {\\n        recovered = ecrecover(hash, v, signature.r, signature.s);\\n    } else {\\n        revert("invalid sign method");\\n    }\\n\\n    return signerAddress == recovered;\\n}\\n```\\n

Impact:

Recommended mitigation:
Include the `chain-id` in the signature to avoid cross-chain validity of signatures\\nverify `s` is within valid bounds to avoid signature malleability\\n```\\nif (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n      revert("ECDSA: invalid signature 's' value");\\n }\\n```\\n\\nverify `v` is within valid bounds\\n```\\nif (v != 27 && v != 28) {\\n     revert("ECDSA: invalid signature 'v' value");\\n}\\n```\\n\\nreturn invalid if the result of `ecrecover()` is `0x0`
Vulnerability: Exchange - validateOrderParam does not check against SUPPORTED_ORDER_VERSION
Severity: medium

Description:
`validateOrderParam` verifies the signature and version of a provided order. Instead of checking against the contract constant `SUPPORTED_ORDER_VERSION` it, however, checks against a hardcoded version `2` in the method itself.\\nThis might be a problem if `SUPPORTED_ORDER_VERSION` is seen as the configuration parameter for the allowed version. Changing it would not change the allowed order version for `validateOrderParam` as this constant literal is never used.\\nAt the time of this audit, however, the `SUPPORTED_ORDER_VERSION` value equals the hardcoded value in the `validateOrderParam` method.\\n```\\nfunction validateOrderParam(IPerpetual perpetual, LibOrder.OrderParam memory orderParam)\\n    internal\\n    view\\n    returns (bytes32)\\n{\\n    address broker = perpetual.currentBroker(orderParam.trader);\\n    require(broker == msg.sender, "invalid broker");\\n    require(orderParam.getOrderVersion() == 2, "unsupported version");\\n    require(orderParam.getExpiredAt() >= block.timestamp, "order expired");\\n\\n    bytes32 orderHash = orderParam.getOrderHash(address(perpetual), broker);\\n    require(orderParam.signature.isValidSignature(orderHash, orderParam.trader), "invalid signature");\\n    require(filled[orderHash] < orderParam.amount, "fullfilled order");\\n\\n    return orderHash;\\n}\\n```\\n

Impact:

Recommended mitigation:
Check against `SUPPORTED_ORDER_VERSION` instead of the hardcoded value `2`.
Vulnerability: LibMathSigned - wpowi returns an invalid result for a negative exponent  Pending
Severity: medium

Description:
`LibMathSigned.wpowi(x,n)` calculates Wad value `x` (base) to the power of `n` (exponent). The exponent is declared as a signed int, however, the method returns wrong results when calculating `x ^(-n)`.\\nThe comment for the `wpowi` method suggests that `n` is a normal integer instead of a Wad-denominated value. This, however, is not being enforced.\\n`LibMathSigned.wpowi(8000000000000000000, 2) = 64000000000000000000`\\n(wrong) `LibMathSigned.wpowi(8000000000000000000, -2) = 64000000000000000000`\\n```\\n// x ^ n\\n// NOTE: n is a normal integer, do not shift 18 decimals\\n// solium-disable-next-line security/no-assign-params\\nfunction wpowi(int256 x, int256 n) internal pure returns (int256 z) {\\n    z = n % 2 != 0 ? x : \\_WAD;\\n\\n    for (n /= 2; n != 0; n /= 2) {\\n        x = wmul(x, x);\\n\\n        if (n % 2 != 0) {\\n            z = wmul(z, x);\\n        }\\n    }\\n}\\n```\\n

Impact:

Recommended mitigation:
Make `wpowi` support negative exponents or use the proper type for `n` (uint) and reject negative values.\\nEnforce that the exponent bounds are within sane ranges and less than a Wad to detect potential misuse where someone accidentally provides a Wad value as `n`.\\nAdd positive and negative unit-tests to fully cover this functionality.
Vulnerability: Outdated solidity version and floating pragma  Pending
Severity: medium

Description:
Using an outdated compiler version can be problematic especially if there are publicly disclosed bugs and issues (see also https://github.com/ethereum/solidity/releases) that affect the current compiler version.\\nThe codebase specifies a floating version of `^0.5.2` and makes use of the experimental feature `ABIEncoderV2`.\\nIt should be noted, that `ABIEncoderV2` was subject to multiple bug-fixes up until the latest 0.6.xversion and contracts compiled with earlier versions are - for example - susceptible to the following issues:\\nImplicitConstructorCallvalueCheck\\nTupleAssignmentMultiStackSlotComponents\\nMemoryArrayCreationOverflow\\nprivateCanBeOverridden\\nYulOptimizerRedundantAssignmentBreakContinue0.5\\nABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers\\nSignedArrayStorageCopy\\nABIEncoderV2StorageArrayWithMultiSlotElement\\nDynamicConstructorArgumentsClippedABIV2\\nCodebase declares compiler version ^0.5.2:\\n```\\npragma solidity ^0.5.2;\\npragma experimental ABIEncoderV2; // to enable structure-type parameters\\n```\\n\\nAccording to etherscan.io, the currently deployed main-net `AMM` contract is compiled with solidity version 0.5.8:\\nhttps://etherscan.io/address/0xb95B9fb0539Ec84DeD2855Ed1C9C686Af9A4e8b3#code

Impact:

Recommended mitigation:
It is recommended to settle on the latest stable 0.6.x or 0.5.x version of the Solidity compiler and lock the pragma version to a specifically tested compiler release.
Vulnerability: AMM - ONE_WAD_U is never used
Severity: low

Description:
The const `ONE_WAD_U` is declared but never used. Avoid re-declaring the same constants in multiple source-units (and unit-test cases) as this will be hard to maintain.\\n```\\nuint256 private constant ONE\\_WAD\\_U = 10\\*\\*18;\\n```\\n

Impact:

Recommended mitigation:
Remove unused code. Import the value from a shared resource. E.g.ONE_WAD is declared multiple times in `LibMathSigned`, `LibMathUnsigned`, `AMM`, hardcoded in checks in `PerpetualGovernance.setGovernanceParameter`, `AMMGovernance.setGovernanceParameter`.
Vulnerability: Perpetual - Variable shadowing in constructor
Severity: low

Description:
`Perpetual` inherits from `PerpetualGovernance` and `Collateral`, which declare state variables that are shadowed in the `Perpetual` constructor.\\nLocal constructor argument shadows `PerpetualGovernance.globalConfig`, `PerpetualGovernance.devAddress`, `Collateral.collateral`\\nNote: Confusing name: `Collateral` is an inherited contract and a state variable.\\n```\\nconstructor(address globalConfig, address devAddress, address collateral, uint256 collateralDecimals)\\n    public\\n    Position(collateral, collateralDecimals)\\n{\\n    setGovernanceAddress("globalConfig", globalConfig);\\n    setGovernanceAddress("dev", devAddress);\\n    emit CreatePerpetual();\\n}\\n```\\n

Impact:

Recommended mitigation:
Rename the parameter or state variable.
Vulnerability: Perpetual - The specified decimals for the collateral may not reflect the token's actual decimals  Acknowledged
Severity: low

Description:
When initializing the `Perpetual` contract, the deployer can decide to use either `ETH`, or an ERC20-compliant collateral. In the latter case, the deployer must provide a nonzero address for the token, as well as the number of `decimals` used by the token:\\n```\\nconstructor(address \\_collateral, uint256 decimals) public {\\n    require(decimals <= MAX\\_DECIMALS, "decimals out of range");\\n    require(\\_collateral != address(0x0) || (\\_collateral == address(0x0) && decimals == 18), "invalid decimals");\\n\\n    collateral = \\_collateral;\\n    scaler = (decimals == MAX\\_DECIMALS ? 1 : 10\\*\\*(MAX\\_DECIMALS - decimals)).toInt256();\\n}\\n```\\n\\nThe provided `decimals` value is not checked for validity and can differ from the actual token's `decimals`.

Impact:

Recommended mitigation:
Ensure to establish documentation that makes users aware of the fact that the decimals configured are not enforced to match the actual tokens decimals. This is to allow users to audit the system configuration and decide whether they want to participate in it.
Vulnerability: AMM - Unchecked return value in ShareToken.mint  Pending
Severity: low

Description:
`ShareToken` is an extension of the Openzeppelin ERC20Mintable pattern which exposes a method called `mint()` that allows accounts owning the minter role to mint new tokens. The return value of `ShareToken.mint()` is not checked.\\nSince the ERC20 standard does not define whether this method should return a value or revert it may be problematic to assume that all tokens revert. If, for example, an implementation is used that does not revert on error but returns a boolean error indicator instead the caller might falsely continue without the token minted.\\nWe would like to note that the functionality is intended to be used with the provided `ShareToken` and therefore the contract is safe to use assuming `ERC20Mintable.mint` reverts on error. The issue arises if the system is used with a different `ShareToken` implementation that is not implemented in the same way.\\nOpenzeppelin implementation\\n```\\nfunction mint(address account, uint256 amount) public onlyMinter returns (bool) {\\n    \\_mint(account, amount);\\n    return true;\\n}\\n```\\n\\nCall with unchecked return value\\n```\\nfunction mintShareTokenTo(address guy, uint256 amount) internal {\\n    shareToken.mint(guy, amount);\\n}\\n```\\n

Impact:

Recommended mitigation:
Consider wrapping the `mint` statement in a `require` clause, however, this way only tokens that are returning a boolean error indicator are supported. Document the specification requirements for the `ShareToken` and clearly state if the token is expected to revert or return an error indicator.\\nIt should also be documented that the Token exposes a `burn` method that does not adhere to the Openzeppelin `ERC20Burnable` implementation. The `ERC20Burnable` import is unused as noted in issue 6.23.
Vulnerability: Perpetual - beginGlobalSettlement can be called multiple times  Acknowledged
Severity: low

Description:
The system can be put into emergency mode by an admin calling `beginGlobalSettlement` and providing a fixed `settlementPrice`. The method can be invoked even when the contract is already in `SETTLING` (emergency) mode, allowing an admin to selectively adjust the settlement price again. This does not seem to be the intended behavior as calling the method again re-sets the status to `SETTLING`. Furthermore, it may affect users' behavior during the `SETTLING` phase.\\n```\\nfunction beginGlobalSettlement(uint256 price) public onlyWhitelistAdmin {\\n    require(status != LibTypes.Status.SETTLED, "already settled");\\n    settlementPrice = price;\\n    status = LibTypes.Status.SETTLING;\\n    emit BeginGlobalSettlement(price);\\n}\\n```\\n

Impact:

Recommended mitigation:
Emergency mode should only be allowed to be set once
Vulnerability: Exchange - OrderStatus is never used
Severity: low

Description:
The enum `OrderStatus` is declared but never used.\\n```\\nenum OrderStatus {EXPIRED, CANCELLED, FILLABLE, FULLY\\_FILLED}\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nThis issue was resolved by removing the unused code.\\nRemove unused code.
Vulnerability: LibMath - Inaccurate declaration of _UINT256_MAX
Severity: low

Description:
`LibMathUnsigned` declares `_UINT256_MAX` as `2^255-1` while this value actually represents `_INT256_MAX`. This appears to just be a naming issue.\\n(UINT256_MAX/2-1 => pos INT256_MAX; 2**256/2-1==2**255-1)\\n```\\nlibrary LibMathUnsigned {\\n    uint256 private constant \\_WAD = 10\\*\\*18;\\n    uint256 private constant \\_UINT256\\_MAX = 2\\*\\*255 - 1;\\n```\\n

Impact:

Recommended mitigation:
Rename `_UINT256_MAX` to `_INT256MAX` or `_SIGNED_INT256MAX`.
Vulnerability: LibMath - inconsistent assertion text and improve representation of literals with many digits  Acknowledged
Severity: low

Description:
The assertion below states that `logE only accepts v <= 1e22 * 1e18` while the argument name is `x`. In addition to that we suggest representing large literals in scientific notation.\\n```\\nfunction wln(int256 x) internal pure returns (int256) {\\n    require(x > 0, "logE of negative number");\\n    require(x <= 10000000000000000000000000000000000000000, "logE only accepts v <= 1e22 \\* 1e18"); // in order to prevent using safe-math\\n    int256 r = 0;\\n    uint8 extra\\_digits = longer\\_digits - fixed\\_digits;\\n```\\n

Impact:

Recommended mitigation:
Update the inconsistent assertion text `v` -> `x` and represent large literals in scientific notation as they are otherwise difficult to read and review.