SCWE-110: Fee-On-Transfer Token Misaccounting
Stable Version v1.0
This content is in the version-(v1.0) and still under active development, so it is subject to change any time (e.g. structure, IDs, content, URLs, etc.).
Relationships¶
- CWE-682: Incorrect Calculation
https://cwe.mitre.org/data/definitions/682.html
Description¶
Assuming an ERC20 transfer moves the full requested amount fails with fee-on-transfer or deflationary tokens. Protocols that credit users for the requested amount instead of the received amount can be drained or mis-account balances.
Remediation¶
- Measure token balances before and after transfers to calculate the actual received amount.
- Maintain allowlists/blocks for incompatible tokens or handle fee-on-transfer explicitly.
- Validate that accounting uses the net amount when updating shares or debts.
Examples¶
Vulnerable¶
pragma solidity ^0.8.0;
contract Vault {
IERC20 public token;
mapping(address => uint256) public deposits;
function deposit(uint256 amount) external {
token.transferFrom(msg.sender, address(this), amount);
deposits[msg.sender] += amount; // credits full amount even if fee applied
}
}
Fixed¶
pragma solidity ^0.8.0;
contract Vault {
IERC20 public token;
mapping(address => uint256) public deposits;
function deposit(uint256 amount) external {
uint256 beforeBal = token.balanceOf(address(this));
token.transferFrom(msg.sender, address(this), amount);
uint256 received = token.balanceOf(address(this)) - beforeBal;
deposits[msg.sender] += received; // credit net amount
}
}