You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The protocol computes a factor when minting (and burning) tokens which is the exchange rate of rebase to base tokens (base supply / total assets value), see GToken.factor().
The first user can manipulate this factor such that it always returns 0.
Example:
Attacker deposits 100.0 DAI and mints 100 * 1e18 PWRD: DepositHandler.depositGToken with dollarAmount = 100.0 = 100 * 1e18, then ctrl.mintGToken(pwrd, msg.sender, 1e18)
calls gt.mint(account, gt.factor(), amount=1e18) where gt.factor() returns getInitialBase() = 1e18 because the person is the first minter and it mints amount * factor / _BASE = 1e18
The ctrl.mintGToken call also increases total assets: pnl.increaseGTokenLastAmount(...)
The attacker now burns (withdraws) all minted tokens again except a single wei using one of the withdrawal functions in WithdrawHandler. Because of the withdrawal fee the total assets are only decreased by the post-fee amount (IPnL(pnl).decreaseGTokenLastAmount(pwrd, amount=userBalance - 1, bonus=fee);), i.e., with a 2% withdrawal fee the total assets stay at 2% of 100$ = 2 * 1e18.
The result is that GToken.factor() always returns totalSupplyBase().mul(BASE).div(totalAssets) = 1 * 1e18 / (2 * 1e18) = 0
Impact
The resulting factor is 0 and thus any user deposits by depositGToken will mint 0 base tokens to the depositor.
This means all deposits and future value accrues to the attacker who holds the only base tokens.
An attacker could even frontrun the first minter to steal their deposit this way.
Recommended Mitigation Steps
Uniswap solves a similar problem by sending the first 1000 tokens to the zero address which makes the attack 1000x more expensive.
The same should work here, i.e., on first mint (total base supply == 0), lock some of the first minter's tokens by minting ~1% of the initial amount to the zero address instead of to the first minter.
The text was updated successfully, but these errors were encountered:
Even though it's a known issue its consequences are significant. Only because it can be mitigated by ops quite easily, I'll degrade it to medium level.
Handle
cmichel
Vulnerability details
Vulnerability Details
The protocol computes a
factor
when minting (and burning) tokens which is the exchange rate of rebase to base tokens (base supply / total assets value), seeGToken.factor()
.The first user can manipulate this factor such that it always returns
0
.Example:
DepositHandler.depositGToken
withdollarAmount = 100.0 = 100 * 1e18
, thenctrl.mintGToken(pwrd, msg.sender, 1e18)
calls
gt.mint(account, gt.factor(), amount=1e18)
wheregt.factor()
returnsgetInitialBase() = 1e18
because the person is the first minter and it mintsamount * factor / _BASE = 1e18
ctrl.mintGToken
call also increases total assets:pnl.increaseGTokenLastAmount(...)
WithdrawHandler
. Because of the withdrawal fee the total assets are only decreased by the post-fee amount (IPnL(pnl).decreaseGTokenLastAmount(pwrd, amount=userBalance - 1, bonus=fee);
), i.e., with a 2% withdrawal fee the total assets stay at 2% of 100$ = 2 * 1e18.GToken.factor()
always returnstotalSupplyBase().mul(BASE).div(totalAssets) = 1 * 1e18 / (2 * 1e18) = 0
Impact
The resulting
factor
is 0 and thus any user deposits bydepositGToken
will mint 0 base tokens to the depositor.This means all deposits and future value accrues to the attacker who holds the only base tokens.
An attacker could even frontrun the first minter to steal their deposit this way.
Recommended Mitigation Steps
Uniswap solves a similar problem by sending the first 1000 tokens to the zero address which makes the attack 1000x more expensive.
The same should work here, i.e., on first mint (total base supply == 0), lock some of the first minter's tokens by minting ~1% of the initial amount to the zero address instead of to the first minter.
The text was updated successfully, but these errors were encountered: