Unhandled Failure of _executeTransaction
Call in executeTransaction
Function Poses Risk of Misrepresentation of Transaction Status
Submitted on Feb 24th 2024 at 00:15:20 UTC by @ihtishamsudo for Boost | Puffer Finance
Report ID: #28688
Report type: Smart Contract
Report severity: Insight
Target: https://etherscan.io/address/0x3C28B7c7Ba1A1f55c9Ce66b263B33B204f2126eA#code
Impacts:
- Contract fails to deliver promised returns, but doesn't lose value
The executeTransaction
function in Timelock.sol
does not handle the case where _executeTransaction
call fails because bool only does not revert
but returns true or false
When a transaction is executed via executeTransaction
the _executeTransaction
is called. This _executeTransaction
function is a low-level
call that forward call with payload to another contract or address.
The problem is that if this call fails if doesn't throw any exception, but instead it returns false as a success value.
function _executeTransaction(address target, bytes calldata callData) internal returns (bool, bytes memory) {
// slither-disable-next-line arbitrary-send-eth
return target.call(callData);
}
However, calling function executeTransaction
doesn't handle the failure case.
the TransactionExecuted event is emitted regardless of the success of the _executeTransaction
call.
If the _executeTransaction call fails, it's likely that something went wrong with the transaction. However, the executeTransaction function would still emit the TransactionExecuted event and return false and an empty bytes array. This could lead to a false sense of successful transaction execution. In a worst-case scenario, this could result in loss of funds or incorrect state changes if actions are taken based on the incorrect assumption that the transaction was successful.
To handle the failure case, you could add a condition to check the success value and revert the transaction if the call failed
function executeTransaction(address target, bytes calldata callData, uint256 operationId)
external
returns (bool success, bytes memory returnData)
{
Code....
queue[txHash] = 0;
(success, returnData) = _executeTransaction(target, callData);
+ if (!success) {
+ revert ("Transaction Failed");
+ }
emit TransactionExecuted(txHash, target, callData, operationId);
return (success, returnData);
}
N/A