Rebasing Token Remediation
Overview
Related Detector: Rebasing Token
Elastic-supply tokens (stETH, AMPL, and similar) change holder balances between transactions without a transfer. A vault that records “user deposited 100” and later returns 100 pays out the wrong amount after a rebase — too much, draining the vault, or too little, stranding users. The remediation is to store a rebase-invariant unit (shares) or to measure the actual balance received, rather than caching a nominal amount.
Recommended Fix
Before (Vulnerable)
mapping(address => uint256) public deposited;
function deposit(uint256 amount) external {
token.transferFrom(msg.sender, address(this), amount);
deposited[msg.sender] += amount; // stale after any rebase
}
After (Fixed — share accounting from measured balances)
mapping(address => uint256) public shares;
uint256 public totalShares;
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; // handles fee-on-transfer too
uint256 minted = totalShares == 0
? received
: (received * totalShares) / before;
shares[msg.sender] += minted;
totalShares += minted;
}
Redemptions then pay shares * currentBalance / totalShares, so each user’s claim tracks rebases automatically.
Common Mistakes
- Storing nominal amounts and assuming
balanceOfwill still match them after a rebase. - Using the transfer argument as the amount received, which breaks for both rebasing and fee-on-transfer tokens; measure the delta.
- Allowing arbitrary rebasing tokens into a vault designed around fixed balances without an explicit allowlist.