Missing validation check on ERC-20 transfer
Description
The Transferable contract is used to handle native and ERC-20 tokens with a common contract. The native token is detected if the token
address is zero. The transfer
function checks if the token address is zero and uses either call
or the ERC-20 transfer
function to transfer tokens:
function transfer(address recipient, uint256 amount) internal {
if (token == address(0)) {
(bool success,) = recipient.call{value: amount}("");
require(success, "Native token transfer failed");
} else {
IERC20(token).transfer(recipient, amount);
}
}
However, the success of the ERC-20 transfer operation is not verified. If the transfer fails, the transfer
function will not revert, potentially leading to unexpected behavior or silent failures.
Impact
If a transfer fails during an airdrop claim, the airdrop will still be marked as claimed, but the corresponding amount will not be transferred, leading to a loss of funds. A similar issue occurs during stream creation and reward claiming, where failed transfers result in the amounts not being transferred as expected.
Recommendations
To mitigate this issue, the safeTransfer
function from the SafeERC20 library can be used in place of transfer
. Additionally, a test should be implemented to verify these scenarios, ensuring that the contract handles failed transfers correctly and behaves as expected under such conditions.
Remediation
This issue has been acknowledged by Clique, and a fix was implemented in commit 5dd44079↗. A check on the returned value was implemented, and the transfer
function reverts in case the ERC-20 transfer fails.