Glamorous Plum Baboon
High
In the BorrowLogic
library of the Aave protocol, the functions executeBorrow
and executeRepay
make several external calls to interfaces like IVariableDebtToken
and IAToken
without validating their return values. This oversight could result in unexpected contract behavior if these external calls fail, potentially leading to financial losses or incorrect state changes.
The root cause of the issue is the lack of proper error handling for external function calls. Specifically:
- In
executeBorrow
, the external call tomint()
on theIVariableDebtToken
interface is not checked for success. - In both
executeBorrow
andexecuteRepay
, external calls toIAToken
functions liketransferUnderlyingTo()
andburn()
are not verified to ensure they execute successfully.
Without these checks, failures in these external contracts (e.g., failed token transfers or debt minting) will not revert the transaction or provide feedback to the user, leaving the contract in an inconsistent state.
i, Financial Loss: If the external calls fail (e.g., if the minting of the debt token fails), users may not receive the correct debt or collateral, leading to unexpected financial loss or asset mismanagement. ii, Inconsistent Contract State: Failing to check the results of these external calls could leave the contract in an inconsistent state, where user balances or debt information is inaccurate. iii, Potential for Exploits: A malicious actor could exploit the lack of validation to manipulate or interact with the contract in unintended ways, such as by triggering a state where they are able to avoid debt repayment or withdraw funds that they should not be able to access.
To demonstrate the issue, consider the following scenario:
- A user initiates a borrow operation via
executeBorrow
, which internally calls themint()
function of theIVariableDebtToken
contract. If this call fails (e.g., due to insufficient gas or contract logic failure), the borrow operation will proceed as if the minting was successful, leading to a discrepancy in the user's debt and the contract state. - Similarly, in
executeRepay
, if theburn()
function in theIVariableDebtToken
orIAToken
fails, the contract would incorrectly track the user’s repayment, leading to inconsistent debt records.
-
Check External Call Return Values: Each external function call, such as
mint()
andburn()
, should have its return value checked to confirm that the operation was successful.Example for
mint()
:bool success = IVariableDebtToken(reserveCache.variableDebtTokenAddress).mint( params.user, params.onBehalfOf, params.amount, reserveCache.nextVariableBorrowIndex ); require(success, "Debt token mint failed");
-
Use
require
Statements: Where applicable, userequire
to ensure the success of external calls. This will revert the transaction in case of failure, preventing any inconsistencies in the contract state. -
Implement Revert Messages: Provide meaningful revert messages that will help in debugging if the external calls fail. This can help developers and auditors quickly pinpoint where failures occur.
TAKE HOME
1, This bug was found in the executeBorrow
and executeRepay
functions but could be applicable to other similar functions in the contract or related libraries.
2, It is important to always validate the return values of external calls in Solidity to ensure the robustness and security of the contract.
3, Adding checks for external calls is a best practice that aligns with the security principles of smart contract development.