Balance Accounting Mismatch Remediation
Overview
Related Detector: Balance Accounting Mismatch
Recording a deposit using the amount passed to transferFrom assumes the contract received exactly that much. For fee-on-transfer, deflationary, or rebasing tokens, the amount received differs from the amount requested — so the books over-credit the user and the vault becomes insolvent. The remediation is to measure the actual balance change and account for that.
Recommended Fix
Before (Vulnerable)
function deposit(uint256 amount) external {
token.transferFrom(msg.sender, address(this), amount);
balances[msg.sender] += amount; // wrong if the token took a fee
}
After (Fixed — credit the measured delta)
function deposit(uint256 amount) external {
uint256 before = token.balanceOf(address(this));
token.transferFrom(msg.sender, address(this), amount);
uint256 received = token.balanceOf(address(this)) - before; // what actually arrived
balances[msg.sender] += received;
}
Credit and later pay out the measured received, not the requested amount, so the vault’s liabilities always match its holdings. If your protocol cannot support non-standard tokens, reject them explicitly with an allowlist rather than mis-accounting.
Common Mistakes
- Measuring the delta on deposit but paying out the nominal amount on withdrawal, reintroducing the mismatch.
- Using the balance-delta pattern while a reentrant token hook lets the balance change mid-measurement — combine with a reentrancy guard.
- Assuming a token is standard because it “looks like” ERC-20; fee-on-transfer behaviour is not visible from the interface.