MEDIUM severity: The vulnerability in the RocketMinipoolDelegateOld contract allows a node operator to manipulate acc. The vulnerability in the RocketMinipoolDelegateOld contract allows a node operator to manipulate accounting by reentering the `finalise()` function. This is achieved by calling `finalise()` to finalize a Minipool, which triggers a call to `_refund()` to send a refund balance to the `nodeWithdrawalAd...

Vulnerable code:
```\nfinalise() -->\n  status == MinipoolStatus.Withdrawable  // true\n  withdrawalBlock > 0  // true\n  _finalise() -->\n   !finalised  // true\n    _refund()\n      nodeRefundBalance = 0  // reset refund balance\n      extCall: nodeWithdrawalAddress\n      reenter: finalise()\n        status == MinipoolStatus.Withdrawable  // true\n        withdrawalBlock > 0  // true\n        _finalise() -->\n         !finalised  // true\n          nodeRefundBalance > 0  // false; no refund()\n          address(this).balance to RETH\n          RocketTokenRETHInterface(rocketTokenRETH).depositExcessCollateral()\n          rocketMinipoolManager.incrementNodeFinalisedMinipoolCount(nodeAddress)  // 1st time\n          eventually call rocketDAONodeTrusted.decrementMemberUnbondedValidatorCount(nodeAddress)\n          finalised = true\n        <--- return from reentrant call\n      <--- return from _refund()\n    address(this).balance to RETH  // NOP as balance was sent to RETH already\n    RocketTokenRETHInterface(rocketTokenRETH).depositExcessCollateral()  // does not revert\n    rocketMinipoolManager.incrementNodeFinalisedMinipoolCount(nodeAddress)  // no revert, increases\n    'node.minipools.finalised.count','minipools.finalised.count', reduces 'eth.matched.node.amount' one to many times\n    eventually call rocketDAONodeTrusted.decrementMemberUnbondedValidatorCount(nodeAddress)  // manipulates\n   'member.validator.unbonded.count' by +1\n    finalised = true  // is already 'true', gracefully continues\n<--- returns\n```\n```\nfunction finalise() external override onlyInitialised onlyMinipoolOwnerOrWithdrawalAddress(msg.sender) {\n    require(status == MinipoolStatus.Withdrawable, "Minipool must be withdrawable");\n    require(withdrawalBlock > 0, "Minipool balance must have been distributed at least once");\n    _finalise();\n}\n```\n```\nfunction _finalise() private {\n    // Get contracts\n    RocketMinipoolManagerInterface rocketMinipoolManager = \n        RocketMinipoolManagerInterface(getContractAddress("rocketMinipoolManager"));\n\n    // Can only finalise the pool once\n    require(!finalised, "Minipool has already been finalised");\n\n    // If slash is required then perform it\n    if (nodeSlashBalance > 0) {\n        _slash();\n    }\n\n    // Refund node operator if required\n    if (nodeRefundBalance > 0) {\n        _refund();\n    }\n\n    // Send any left over ETH to rETH contract\n    if (address(this).balance > 0) {\n        // Send user amount to rETH contract\n        payable(rocketTokenRETH).transfer(address(this).balance);\n    }\n\n    // Trigger a deposit of excess collateral from rETH contract to deposit pool\n    RocketTokenRETHInterface(rocketTokenRETH).depositExcessCollateral();\n\n    // Unlock node operator's RPL\n    rocketMinipoolManager.incrementNodeFinalisedMinipoolCount(nodeAddress);\n\n    // Update unbonded validator count if minipool is unbonded\n    if (depositType == MinipoolDeposit.Empty) {\n        RocketDAONodeTrustedInterface rocketDAONodeTrusted = \n            RocketDAONodeTrustedInterface(getContractAddress("rocketDAONodeTrusted"));\n        rocketDAONodeTrusted.decrementMemberUnbondedValidatorCount(nodeAddress);\n    }\n\n    // Set finalised flag\n    finalised = true;\n}\n```\n```\nfunction _refund() private {\n    uint256 refundAmount = nodeRefundBalance;\n    nodeRefundBalance = 0;\n\n    address nodeWithdrawalAddress = rocketStorage.getNodeWithdrawalAddress(nodeAddress);\n\n    (bool success,) = nodeWithdrawalAddress.call{value: refundAmount}("");\n    require(success, "ETH refund amount was not successfully transferred to node operator");\n\n    emit EtherWithdrawn(nodeWithdrawalAddress, refundAmount, block.timestamp);\n}\n```\n```\nfunction incrementNodeFinalisedMinipoolCount(address _nodeAddress) override external onlyLatestContract("rocketMinipoolManager", address(this)) onlyRegisteredMinipool(msg.sender) {\n    addUint(keccak256(abi.encodePacked("node.minipools.finalised.count", _nodeAddress)), 1);\n    addUint(keccak256(bytes("minipools.finalised.count")), 1);\n}\n```\n```\n}\nfunction decrementMemberUnbondedValidatorCount(address _nodeAddress) override external onlyLatestContract("rocketDAONodeTrusted", address(this)) onlyRegisteredMinipool(msg.sender) {\n    subUint(keccak256(abi.encodePacked(daoNameSpace, "member.validator.unbonded.count", _nodeAddress)), 1);\n}\n```