Closed c4-submissions closed 1 year ago
GalloDaSballo marked the issue as primary issue
Slightly more detail
0xfoobar (sponsor) acknowledged
Rebase tokens should be wrapped into non-rebasing tokens before being deposited, as with most other basic protocols like Uniswap.
GalloDaSballo changed the severity to QA (Quality Assurance)
Downgrading to QA and will consult with judges over how to handle this
L
GalloDaSballo marked the issue as grade-c
Lines of code
https://github.com/code-423n4/2023-09-delegate/blob/a6dbac8068760ee4fc5bababb57e3fe79e5eeb2e/src/DelegateToken.sol#L311 https://github.com/code-423n4/2023-09-delegate/blob/a6dbac8068760ee4fc5bababb57e3fe79e5eeb2e/src/DelegateToken.sol#L375
Vulnerability details
Impact
Rebasing tokens, such as AMPL or rUSDY, change users' balances over time (for example to maintain the 1$ value). The
DelegateToken
contract saves the exact amount of underlying token at the time of delegation creation. When thePrincipalToken
holder calls thewithdraw()
method, the contract attempts to transfer the previously saved amount. As the result, if the rebasing token's balance has changed, the holder may steal other users' deposits, receive insufficient amount of tokens or not be able to withdraw the deposit at all.Proof of Concept
The
DelegateToken#create()
method escrows the specified amount of token and saves this amount in the registry.https://github.com/code-423n4/2023-09-delegate/blob/a6dbac8068760ee4fc5bababb57e3fe79e5eeb2e/src/DelegateToken.sol#L311-L314
Those tokens may be withdrawn by the
PrincipalToken
holder using theDelegateToken#withdraw()
method. The following code executes the withdrawal:https://github.com/code-423n4/2023-09-delegate/blob/a6dbac8068760ee4fc5bababb57e3fe79e5eeb2e/src/DelegateToken.sol#L371-L375
The amount to withdraw is being read from the registry and it is the exact amount of tokens that was initially escrowed. However, in case of rebasing tokens, the actual underlying balance of the token might change. Therefore the following scenarios may occur:
withdraw()
method caller will receive the original escrowed amount of token, stealing other users depositswithdraw()
method will revert as the balance is not sufficient to execute thesafeTrasfer()
call; the tokens will be stuck in the contractwithdraw()
method caller will only receive the amount equal to his initial deposit; the additional balance accrued in time will be stuck in the contractTools Used
Manual review, Solodit
Recommended Mitigation Steps
The usage of rebasing tokens should be clearly discouraged in the documentation.
If the rebasing tokens have to be used in the protocol, they will require complex handling.
DelegateToken
contract should keep track of the depositor's shares in the total deposit and calculate the amount to withdraw based on the shares and the actualDelegateToken
contract's balance of the underlying token.Assessed type
ERC20