Skip to main content
Sigvex

Fee-on-Transfer Remediation

Measure the actual received balance after transferFrom instead of trusting the requested amount.

Fee-on-Transfer Remediation

Overview

Fee-on-transfer (deflationary) tokens deduct a percentage on every transfer, so a contract that pulls tokens with transferFrom receives less than the nominal amount. Crediting the user with the requested amount makes the protocol undercollateralized; the shortfall compounds until withdrawals can no longer be honored and the last users find the contract insolvent.

Related Detector: Fee-on-Transfer

Before (Vulnerable)

function deposit(address token, uint256 amount) external {
    IERC20(token).transferFrom(msg.sender, address(this), amount);
    balances[msg.sender] += amount;  // Credits full amount
}

After (Fixed)

function deposit(address token, uint256 amount) external {
    uint256 before = IERC20(token).balanceOf(address(this));
    IERC20(token).transferFrom(msg.sender, address(this), amount);
    uint256 received = IERC20(token).balanceOf(address(this)) - before;
    balances[msg.sender] += received;  // Credits actual received
}

Measuring the balance before and after the transfer captures the real amount that arrived, fee included. Internal accounting then matches the contract’s actual token holdings, so withdrawals always have backing.

Alternative Mitigations

  • Maintain an explicit allowlist of vetted non-fee tokens and reject all others, so the requested amount is guaranteed to equal the received amount.
  • Apply the same before/after balance measurement on the withdrawal path when sending tokens out, since fees also apply on outbound transfers.
  • For rebasing or elastic-supply tokens, track shares rather than absolute balances.

Common Mistakes

  • Computing received but still using the original amount later in the function for share or reward math.
  • Reusing a single contract-wide balance snapshot across reentrant or batched deposits, which corrupts the delta.
  • Assuming a token is fee-free because its fee is currently set to zero; some tokens (such as configurable USDT) can enable a fee later.

References