Stratax Contracts

First Flight #57
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: high
Likelihood: high

Tether (USDT) Non-Standard ERC20 Behavior Can Cause Flash Loan Reverts and Protocol Denial of Service

Author Revealed upon completion

Tether (USDT) Non-Standard ERC20 Behavior Can Cause Flash Loan Reverts and Protocol Denial of Service

Description:

The Stratax contract performs multiple direct calls to IERC20.transfer, transferFrom, and approve, assuming strict ERC-20 compliance (i.e., returning bool and supporting standard allowance behavior).

However, Tether (USDT), issued by Tether Limited, is a well-known non-standard ERC-20 implementation with the following characteristics:

  • transfer and transferFrom may not return a boolean value.

  • approve may revert if attempting to change a non-zero allowance directly to another non-zero value.

  • It does not strictly comply with the expected ERC-20 return value behavior.

The contract includes multiple unsafe calls such as:

IERC20(_token).transfer(...)
IERC20(_token).transferFrom(...)
IERC20(_token).approve(...)

without:

  • Using SafeERC20

  • Verifying return values

  • Resetting allowance to zero before updating it

When interacting with USDT, these assumptions may cause unexpected reverts.

Impact:

Severity: High

If USDT is used as:

  • Flash loan token

  • Collateral token

  • Borrow token

the protocol may experience:

  • Reverts during createLeveragedPosition

  • Reverts inside _executeOpenOperation

  • Reverts inside _executeUnwindOperation

  • Reverts in recoverTokens

  • Full flash loan transaction failure

Since flash loans must complete atomically, any revert inside transfer or approval logic will revert the entire transaction.

This may result in:

  • Inability to open leveraged positions

  • Inability to unwind positions

  • Operational denial of service when USDT is used

  • Incompatibility with a major Aave-supported asset

Given USDT’s widespread use in DeFi, this significantly impacts protocol reliability and usability.

Proof of Concept:

Scenario:

  1. A user opens a leveraged position using USDT as _flashLoanToken.

  2. Inside _executeOpenOperation, the contract executes:

IERC20(_asset).approve(address(aavePool), totalCollateral);

If:

  • A previous allowance already exists and is non-zero, and

  • The token is USDT,

the call may revert because USDT requires:

approve(spender, 0);
approve(spender, newAmount);

instead of directly updating a non-zero allowance.

As a result:

  • The approve call reverts

  • The flash loan callback fails

  • The entire transaction reverts

The same issue can occur when approving tokens for the 1inch router or during unwind operations.

Recommended Mitigation:

Use OpenZeppelin’s SafeERC20 for all ERC-20 interactions:

import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
using SafeERC20 for IERC20;

Replace:

  • transfer with safeTransfer

  • transferFrom with safeTransferFrom

  • approve with forceApprove (recommended if available)

If forceApprove is not available, use the reset-to-zero pattern:

function _safeApprove(IERC20 token, address spender, uint256 amount) internal {
token.safeApprove(spender, 0);
token.safeApprove(spender, amount);
}

Apply these changes to:

  • createLeveragedPosition

  • _executeOpenOperation

  • _executeUnwindOperation

  • recoverTokens

Support

FAQs

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

Give us feedback!