Summary
No method is implemented to return excess ETH in the TimelockController.executeBatch function if the EXECUTOR_ROLE sends more ETH than required.
Vulnerability Details
function executeBatch(
address[] calldata targets,
uint256[] calldata values,
bytes[] calldata calldatas,
bytes32 predecessor,
bytes32 salt
) external override payable nonReentrant onlyRole(EXECUTOR_ROLE) {
...
for (uint256 i = 0; i < targets.length; i++) {
(bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]);
if (!success) {
revert CallReverted(id, i);
}
}
emit OperationExecuted(id, targets, values, calldatas, predecessor, salt);
}
There is no method implement on executeBatch to get back excess eth , so excess eth is stuck in this contract.
Impact
Excess ETH is stuck in TimelockController contract. so EXECUTOR_ROLE unable to get it back.
Tools Used
Manual Review
Recommendations
Add this code to recieve excess eth back.
uint256 totalSent;
for (uint256 i = 0; i < targets.length; i++) {
totalSent += values[i];
(bool success, ) = targets[i].call{value: values[i]}(calldatas[i]);
if (!success) revert CallReverted(id, i);
}
if (msg.value > totalSent) {
payable(msg.sender).transfer(msg.value - totalSent);
}