// Vulnerability label: NC1
{"ethBridge.sol":{"content":"pragma solidity 0.4.25;\n\nimport \"./multiOwnable.sol\";\nimport \"./IERC20.sol\";\n\ncontract ethBridge is Multiownable {\n    IERC20 private token;\n\n    mapping(address =\u003e uint256) public tokensSent;\n    mapping(address =\u003e uint256) public tokensRecieved;\n    mapping(address =\u003e uint256) public tokensRecievedButNotSent;\n    address[] public feeOwners;\n    mapping(address =\u003e uint) public feeOwnersIndices;\n    uint256 public fee;\n\n    event FeeOwnersUpdated(address[] previousCallers, address[] newCallers);\n\n    constructor (address _token) public {\n        token = IERC20(_token);\n        feeOwners.push(msg.sender);\n        feeOwnersIndices[msg.sender] = 1;\n        fee = 150000 * 10**9;\n    }\n\n    uint256 amountToSent;\n    bool transferStatus;\n\n    bool avoidReentrancy = false;\n\n    function updateBaseFee(uint256 _feeGwei) public onlyAllOwners {\n        fee = _feeGwei * 10**9;\n    }\n\n    function setOwnersForFee(address[] _feeOwners) public onlyAllOwners {\n        for (uint j = 0; j \u003c owners.length; j++) {\n            delete feeOwnersIndices[owners[j]];\n        }\n        for (uint i = 0; i \u003c _feeOwners.length; i++) {\n            require(_feeOwners[i] != address(0), \"FeeOwners: callers array contains zero\");\n            require(feeOwnersIndices[_feeOwners[i]] == 0, \"FeeOwners: callers array contains duplicates\");\n            require(ownersIndices[_feeOwners[i]] \u003e 0, \"FeeOwners: owners not match to callers\");\n            feeOwnersIndices[_feeOwners[i]] = i + 1;\n        }\n        emit FeeOwnersUpdated(feeOwners, _feeOwners);\n        feeOwners = _feeOwners;\n    }\n\n    function sendTokens(uint256 amount) public {\n        require(msg.sender != address(0), \"Zero account\");\n        require(amount \u003e 0,\"Amount of tokens should be more then 0\");\n        require(token.balanceOf(msg.sender) \u003e= amount,\"Not enough balance\");\n\n        transferStatus = token.transferFrom(msg.sender, address(this), amount);\n        if (transferStatus == true) {\n            tokensRecieved[msg.sender] += amount;\n        }\n    }\n\n    function writeTransaction(address user, uint256 amount) public onlySomeOwners(feeOwners.length) {\n        require(user != address(0), \"Zero account\");\n        require(amount \u003e 0,\"Amount of tokens should be more then 0\");\n        require(!avoidReentrancy);\n\n        avoidReentrancy = true;\n        tokensRecievedButNotSent[user] += amount;\n        avoidReentrancy = false;\n    }\n\n    function recieveTokens(uint256[] memory commissions) public payable {\n        if (tokensRecievedButNotSent[msg.sender] != 0) {\n            require(commissions.length == feeOwners.length, \"The number of commissions and owners does not match\");\n            uint256 sum;\n            for(uint i = 0; i \u003c commissions.length; i++) {\n                sum += commissions[i];\n            }\n            require(msg.value \u003e= sum, \"Not enough ETH (The amount of ETH is less than the amount of commissions.)\");\n            require(msg.value \u003e= feeOwners.length * fee, \"Not enough ETH (The amount of ETH is less than the internal commission.)\");\n\n            for (i = 0; i \u003c feeOwners.length; i++) {\n                uint256 commission = commissions[i];\n                feeOwners[i].transfer(commission);\n            }\n\n            amountToSent = tokensRecievedButNotSent[msg.sender] - tokensSent[msg.sender];\n            token.transfer(msg.sender, amountToSent);\n            tokensSent[msg.sender] += amountToSent;\n        }\n    }\n\n    function withdrawTokens(uint256 amount, address reciever) public onlyAllOwners {\n        require(amount \u003e 0,\"Amount of tokens should be more then 0\");\n        require(reciever != address(0), \"Zero account\");\n        require(token.balanceOf(address(this)) \u003e= amount,\"Not enough balance\");\n\n        token.transfer(reciever, amount);\n    }\n\n    function withdrawETHer(uint256 amount, address reciever) public onlyAllOwners {\n        require(amount \u003e 0,\"Amount of tokens should be more then 0\");\n        require(reciever != address(0), \"Zero account\");\n        require(address(this).balance \u003e= amount,\"Not enough balance\");\n\n        reciever.transfer(amount);\n    }\n}\n"},"IERC20.sol":{"content":"pragma solidity 0.4.25;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller\u0027s account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller\u0027s tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender\u0027s allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller\u0027s\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},"multiOwnable.sol":{"content":"pragma solidity ^0.4.25;\n\ncontract Multiownable {\n\n    // VARIABLES\n\n    uint256 public ownersGeneration;\n    uint256 public howManyOwnersDecide;\n    address[] public owners;\n    bytes32[] public allOperations;\n    address internal insideCallSender;\n    uint256 internal insideCallCount;\n\n    // Reverse lookup tables for owners and allOperations\n    mapping(address =\u003e uint) public ownersIndices; // Starts from 1\n    mapping(bytes32 =\u003e uint) public allOperationsIndicies;\n\n    // Owners voting mask per operations\n    mapping(bytes32 =\u003e uint256) public votesMaskByOperation;\n    mapping(bytes32 =\u003e uint256) public votesCountByOperation;\n\n    // EVENTS\n\n    event OwnershipTransferred(address[] previousOwners, uint howManyOwnersDecide, address[] newOwners, uint newHowManyOwnersDecide);\n    event OperationCreated(bytes32 operation, uint howMany, uint ownersCount, address proposer);\n    event OperationUpvoted(bytes32 operation, uint votes, uint howMany, uint ownersCount, address upvoter);\n    event OperationPerformed(bytes32 operation, uint howMany, uint ownersCount, address performer);\n    event OperationDownvoted(bytes32 operation, uint votes, uint ownersCount,  address downvoter);\n    event OperationCancelled(bytes32 operation, address lastCanceller);\n    \n    // ACCESSORS\n\n    function isOwner(address wallet) public view returns(bool) {\n        return ownersIndices[wallet] \u003e 0;\n    }\n\n    function ownersCount() public view returns(uint) {\n        return owners.length;\n    }\n\n    function allOperationsCount() public view returns(uint) {\n        return allOperations.length;\n    }\n\n    // MODIFIERS\n\n    /**\n    * @dev Allows to perform method by any of the owners\n    */\n    modifier onlyAnyOwner {\n        if (checkHowManyOwners(1)) {\n            bool update = (insideCallSender == address(0));\n            if (update) {\n                insideCallSender = msg.sender;\n                insideCallCount = 1;\n            }\n            _;\n            if (update) {\n                insideCallSender = address(0);\n                insideCallCount = 0;\n            }\n        }\n    }\n\n    /**\n    * @dev Allows to perform method only after many owners call it with the same arguments\n    */\n    modifier onlyManyOwners {\n        if (checkHowManyOwners(howManyOwnersDecide)) {\n            bool update = (insideCallSender == address(0));\n            if (update) {\n                insideCallSender = msg.sender;\n                insideCallCount = howManyOwnersDecide;\n            }\n            _;\n            if (update) {\n                insideCallSender = address(0);\n                insideCallCount = 0;\n            }\n        }\n    }\n\n    /**\n    * @dev Allows to perform method only after all owners call it with the same arguments\n    */\n    modifier onlyAllOwners {\n        if (checkHowManyOwners(owners.length)) {\n            bool update = (insideCallSender == address(0));\n            if (update) {\n                insideCallSender = msg.sender;\n                insideCallCount = owners.length;\n            }\n            _;\n            if (update) {\n                insideCallSender = address(0);\n                insideCallCount = 0;\n            }\n        }\n    }\n\n    /**\n    * @dev Allows to perform method only after some owners call it with the same arguments\n    */\n    modifier onlySomeOwners(uint howMany) {\n        require(howMany \u003e 0, \"onlySomeOwners: howMany argument is zero\");\n        require(howMany \u003c= owners.length, \"onlySomeOwners: howMany argument exceeds the number of owners\");\n        \n        if (checkHowManyOwners(howMany)) {\n            bool update = (insideCallSender == address(0));\n            if (update) {\n                insideCallSender = msg.sender;\n                insideCallCount = howMany;\n            }\n            _;\n            if (update) {\n                insideCallSender = address(0);\n                insideCallCount = 0;\n            }\n        }\n    }\n\n    // CONSTRUCTOR\n\n    constructor() public {\n        owners.push(msg.sender);\n        ownersIndices[msg.sender] = 1;\n        howManyOwnersDecide = 1;\n    }\n\n    // INTERNAL METHODS\n\n    /**\n     * @dev onlyManyOwners modifier helper\n     */\n    function checkHowManyOwners(uint howMany) internal returns(bool) {\n        if (insideCallSender == msg.sender) {\n            require(howMany \u003c= insideCallCount, \"checkHowManyOwners: nested owners modifier check require more owners\");\n            return true;\n        }\n\n        uint ownerIndex = ownersIndices[msg.sender] - 1;\n        require(ownerIndex \u003c owners.length, \"checkHowManyOwners: msg.sender is not an owner\");\n        bytes32 operation = keccak256(abi.encodePacked(msg.data, ownersGeneration));\n\n        require((votesMaskByOperation[operation] \u0026 (2 ** ownerIndex)) == 0, \"checkHowManyOwners: owner already voted for the operation\");\n        votesMaskByOperation[operation] |= (2 ** ownerIndex);\n        uint operationVotesCount = votesCountByOperation[operation] + 1;\n        votesCountByOperation[operation] = operationVotesCount;\n        if (operationVotesCount == 1) {\n            allOperationsIndicies[operation] = allOperations.length;\n            allOperations.push(operation);\n            emit OperationCreated(operation, howMany, owners.length, msg.sender);\n        }\n        emit OperationUpvoted(operation, operationVotesCount, howMany, owners.length, msg.sender);\n\n        // If enough owners confirmed the same operation\n        if (votesCountByOperation[operation] == howMany) {\n            deleteOperation(operation);\n            emit OperationPerformed(operation, howMany, owners.length, msg.sender);\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n    * @dev Used to delete cancelled or performed operation\n    * @param operation defines which operation to delete\n    */\n    function deleteOperation(bytes32 operation) internal {\n        uint index = allOperationsIndicies[operation];\n        if (index \u003c allOperations.length - 1) { // Not last\n            allOperations[index] = allOperations[allOperations.length - 1];\n            allOperationsIndicies[allOperations[index]] = index;\n        }\n        //allOperations.length-1\n        allOperations.push(allOperations[allOperations.length-1]);\n\n        delete votesMaskByOperation[operation];\n        delete votesCountByOperation[operation];\n        delete allOperationsIndicies[operation];\n    }\n\n    // PUBLIC METHODS\n\n    /**\n    * @dev Allows owners to change their mind by cacnelling votesMaskByOperation operations\n    * @param operation defines which operation to delete\n    */\n    function cancelPending(bytes32 operation) public onlyAnyOwner {\n        uint ownerIndex = ownersIndices[msg.sender] - 1;\n        require((votesMaskByOperation[operation] \u0026 (2 ** ownerIndex)) != 0, \"cancelPending: operation not found for this user\");\n        votesMaskByOperation[operation] \u0026= ~(2 ** ownerIndex);\n        uint operationVotesCount = votesCountByOperation[operation] - 1;\n        votesCountByOperation[operation] = operationVotesCount;\n        emit OperationDownvoted(operation, operationVotesCount, owners.length, msg.sender);\n        if (operationVotesCount == 0) {\n            deleteOperation(operation);\n            emit OperationCancelled(operation, msg.sender);\n        }\n    }\n\n    /**\n    * @dev Allows owners to change ownership\n    * @param newOwners defines array of addresses of new owners\n    */\n    function transferOwnership(address[] memory newOwners) public {\n        transferOwnershipWithHowMany(newOwners, newOwners.length);\n    }\n\n    /**\n    * @dev Allows owners to change ownership\n    * @param newOwners defines array of addresses of new owners\n    * @param newHowManyOwnersDecide defines how many owners can decide\n    */\n    function transferOwnershipWithHowMany(address[] memory newOwners, uint256 newHowManyOwnersDecide) public onlyManyOwners {\n        require(newOwners.length \u003e 0, \"transferOwnershipWithHowMany: owners array is empty\");\n        require(newOwners.length \u003c= 256, \"transferOwnershipWithHowMany: owners count is greater then 256\");\n        require(newHowManyOwnersDecide \u003e 0, \"transferOwnershipWithHowMany: newHowManyOwnersDecide equal to 0\");\n        require(newHowManyOwnersDecide \u003c= newOwners.length, \"transferOwnershipWithHowMany: newHowManyOwnersDecide exceeds the number of owners\");\n\n        // Reset owners reverse lookup table\n        for (uint j = 0; j \u003c owners.length; j++) {\n            delete ownersIndices[owners[j]];\n        }\n        for (uint i = 0; i \u003c newOwners.length; i++) {\n            require(newOwners[i] != address(0), \"transferOwnershipWithHowMany: owners array contains zero\");\n            require(ownersIndices[newOwners[i]] == 0, \"transferOwnershipWithHowMany: owners array contains duplicates\");\n            ownersIndices[newOwners[i]] = i + 1;\n        }\n        \n        emit OwnershipTransferred(owners, howManyOwnersDecide, newOwners, newHowManyOwnersDecide);\n        owners = newOwners;\n        howManyOwnersDecide = newHowManyOwnersDecide;\n        // allOperations.length = 0;\n        allOperations.push(allOperations[0]);\n        ownersGeneration++;\n    }\n\n}"}}