Stratax Contracts

First Flight #57
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

Fee-on-Transfer Tokens Not Supported

Fee-on-Transfer Tokens Not Supported

Description

  • The protocol assumes that the amount transferred via transferFrom equals the amount received by the contract. This holds for standard ERC20 tokens but fails for fee-on-transfer tokens, which charge a fee on each transfer so the receiver gets less than the sent amount.

  • When opening a leveraged position, the contract computes totalCollateral = _amount + flashParams.collateralAmount and supplies it to Aave. The collateralAmount is the value passed by the caller, not the actual amount received. With fee-on-transfer tokens, the contract receives less than collateralAmount, so it does not hold enough tokens to supply totalCollateral. The supply call reverts due to insufficient balance.

// Transfer the user's collateral to the contract
@> IERC20(_flashLoanToken).transferFrom(msg.sender, address(this), _collateralAmount);
FlashLoanParams memory params = FlashLoanParams({
collateralToken: _flashLoanToken,
collateralAmount: _collateralAmount,
...
});
...
// _executeOpenOperation
uint256 totalCollateral = _amount + flashParams.collateralAmount;
@> IERC20(_asset).approve(address(aavePool), totalCollateral);
@> aavePool.supply(_asset, totalCollateral, address(this), 0);

Risk

Likelihood (low):

  • Aave reserves and typical leverage flows use standard tokens (USDC, WETH) that are not fee-on-transfer.

  • Protocol expansion or integration with staking/reward tokens (e.g. some PAXG, deflationary tokens) would expose this.

Impact (low):

  • createLeveragedPosition reverts when the collateral token is fee-on-transfer.

  • No fund loss; operations fail with "insufficient balance" or similar revert.

Severity (low):

Proof of Concept

// Fee-on-transfer token: 1% fee on transfer
// User approves and calls createLeveragedPosition with collateralAmount = 1000e18
// transferFrom sends 1000e18, contract receives 990e18 (1% fee)
// totalCollateral = flashLoanAmount + 1000e18
// supply(_asset, totalCollateral, ...) attempts to transfer totalCollateral from contract
// Contract only holds flashLoanAmount + 990e18 → revert (insufficient balance)

Recommended Mitigation

Option A — Measure actual received amount and use it in accounting:

require(_collateralAmount > 0, "Collateral Cannot be Zero");
// Transfer the user's collateral to the contract
+ uint256 balanceBefore = IERC20(_flashLoanToken).balanceOf(address(this));
IERC20(_flashLoanToken).transferFrom(msg.sender, address(this), _collateralAmount);
+ uint256 actualReceived = IERC20(_flashLoanToken).balanceOf(address(this)) - balanceBefore;
+ require(actualReceived > 0, "No collateral received");
FlashLoanParams memory params = FlashLoanParams({
collateralToken: _flashLoanToken,
- collateralAmount: _collateralAmount,
+ collateralAmount: actualReceived,
...
});

Option B — Document and enforce: explicitly disallow fee-on-transfer tokens in supported token list; add validation or whitelist if such tokens must be excluded.

Updates

Lead Judging Commences

izuman Lead Judge 16 days ago
Submission Judgement Published
Invalidated
Reason: Out of scope
Assigned finding tags:

WEIRD ERC20 Tokens

Currently there is no support for weird ERC20 tokens i.e. FOT tokens, missing return values, reentrancy etc.

Support

FAQs

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

Give us feedback!