This review is based on the rebasing design described in the article βCoding a Solidity rebase tokenβ. It evaluates potential vulnerabilities and provides recommendations within the context of the rebasing mechanism.
- Verify share and asset calculation formulas
- Review slippage calculation logic during share issuance
- Inspect mint, burn, and transfer logic for accurate share/asset handling
- Handle dust rounding errors in
_amountToShare()
during burn and transfer
Anyone can directly theft over-rebasing assets that have been inflated donated via burn()
.
The current implementation is vulnerable to a small deposit attack, where shares may round down to zero:
"Since there is no 0 share check in
burn()
, attackers can exploit over-rebasing assets."
β Coding a Solidity rebase token
To mitigate zero-share rounding, the original formula is scaled:
sharesToCreate * 10,000 * address(this).balance >= slippageBp * msg.value * _totalShares
When slippageBp = 0
, the user is fully exposed to rebasing volatility.
Actors:
bob
: Owneralice
: Attackercharlie
: Innocent User
Steps:
- Pool starts with 0 shares (no bootstrap).
alice
mints with1 wei
to preempt a small share.charlie
mints1 ETH
withslippageBp = 0
.alice
frontruns and donates100 ETH
, causingcharlie
's share to round to 0.alice
tries toburn()
the pool, butcharlie
frontruns and burns first.- Result:
charlie
steals 101 ETH despite holding 0 shares.
function test_sx() public {
vm.prank(alice);
token.mint{value: 1 wei}(alice, 0);
vm.prank(alice);
address(token).call{value: 100 ether}("");
vm.prank(charlie);
token.mint{value: 1 ether}(charlie, 0);
vm.prank(charlie);
token.burn(charlie, 101 ether);
}
Explanation:
In the formula:
(amount * _totalShares) / address(this).balance
If the result is 0
due to integer division, but burn()
lacks a zero-share check, then rebased assets can be stolen.
-
Revert
burn()
if_amountToShares()
returns 0. -
Apply a Virtual Offset in
mint()
to prevent early ratio distortion:VOFFSET = 1; sharesToCreate = msg.value * (_totalShares + VOFFSET) / (prevBalance + VOFFSET);
This avoids division by zero and stabilizes minting when balance or
_totalShares
is near 0. -
Do NOT apply offset to
burn()
β rebasing effects from donations should be preserved accurately in withdrawals.
check below patch.sol
- Ensure
slippageBp
is within (0,10,000] - Revert if
msg.value == 0
duringmint()