RebateFi Hook

First Flight #53
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Severity: medium
Valid

withdrawTokens Uses Bare IERC20.transfer Without Checking Return

Root + Impact

Description

The withdrawTokens function uses IERC20.transfer() directly.
Some ERC20 tokens (e.g., USDT-style tokens or proxy tokens) return false instead of reverting when a transfer fails.

Since the code does not check the return value, failed transfers silently succeed from the hook’s perspective.
The event still emits, making it appear that tokens were withdrawn when they were not.

function withdrawTokens(address token, address to, uint256 amount) external onlyOwner {
@> IERC20(token).transfer(to, amount); // No success check — may fail silently
emit TokensWithdrawn(token, to, amount);
}

Risk

Likelihood:

  • Triggered whenever the hook tries to withdraw non-standard ERC20 tokens.

  • Common tokens such as USDT exhibit this behavior.

  • Silent transfer failures occur regularly when interacting with diverse assets.

Impact:

  • Tokens may remain stuck in the hook without the owner realizing.

  • Off-chain systems will falsely record successful withdrawals due to the event emission.

  • Can lead to accounting errors, treasury mismanagement, or permanent loss of funds.

Proof of Concept

// Token implementation (simplified)
contract TokenReturningFalse is IERC20 {
function transfer(address, uint256) external returns (bool) {
return false; // Does NOT revert, but indicates failure
}
}
// Hook withdrawal:
withdrawTokens(address(tokenReturningFalse), owner, 1000);
// Behavior:
// - transfer() returns false
// - No revert occurs
// - TokensWithdrawn event is still emitted
// => Off-chain systems believe withdrawal succeeded

This demonstrates that the hook logs a successful withdrawal even when the transfer failed.

Recommended Mitigation

Use SafeERC20.safeTransfer() to guarantee revert-on-failure behavior.

function withdrawTokens(address token, address to, uint256 amount) external onlyOwner {
- IERC20(token).transfer(to, amount);
+ IERC20(token).safeTransfer(to, amount);
emit TokensWithdrawn(token, to, amount);
}

This ensures all ERC20 transfer failures properly revert and cannot be silently ignored.

Updates

Lead Judging Commences

chaossr Lead Judge 8 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Not using safe transfer for ERC20.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!