rETH can be stuck in the BridgeReth
contract because of rocketETH token becoming more valuable as more ETH liquidity is deposited in the rocket pool.
Let's consider the following example:
Let's imagine that in the rocketDeposit
pool we have 1000 minted rETH which is backed up by 2000 ETH. This means that 1rETH = 2ETH. Now the DittoETH protocol becomes live and users start using it.
Alice sends 2 ETH through the depositETH
function in BridgeRouterFacet
using the BridgeReth
contract address. Now the depositETH
function calls the depositEth
function in BridgeReth
and passes the msg.value
which is 2 ETH. We then call rocketDepositPool.deposit{value: msg.value}()
which does some checks and then calls rocketTokenRETH.mint(depositNet, msg.sender)
where depositNet
is our msg.value - depositFee
and the msg.sender
is the BridgeReth
contract. Then we go to the mint
function of the rETH token contract where we get the rETH value using the ETH we send minus the depositFee
. This ETH is converted to rETH by using the formula - _ethAmount.mul(rethSupply).div(totalEthBalance)
. So in our example this would be: (2ETH - depositFee)*1000e18/2000e18 = 1rETH approximately(we are going to round it up to make it easier). So now our BridgeReth
contract gets 1rETH and the rocket supply increases to 1001rETH and the ETH tokens are now 2002ETH. Alice's ethEscrowed
becomes 2zETH(or 2ETH since we assume 1zETH = 1ETH).
Now let's say the ETH liquidity increases and this can happen by various ways. For example users can provide ETH without minting rETH and then the rETH supply stays the same while the ETH supply increases which means rETH becomes more valuable. This can happen since according to Etherscan right now 1rETH trades for about 1.09ETH. Now the ETH tokens increase to let's say 2100ETH and the rETH tokens are still 1001rETH.
Alice wants to withdraw her deposit so she calls the withdraw
function in the BridgeRouterFacet
contract and passes as arguments the BridgeRouter
address and the amount she wants to withdraw(2zETH). After some protocol fees are taken now we go to the withdraw
function of the bridge. There we get the rETH value from the 2zETH Alice wants to withdraw. But now since rETH has become more valuable Alice would get less rETH transferred. The rethValue
would be 2*1001/2100 = 0,95rETH. Then a transfer is called and the rethValue
is transferred to Alice. The BridgeReth
is left with 0,05rETH that cannot be withdrawn since if Alice tries to call withdraw
again the function will revert because the Alice ethEscrow
amount will be 0 and when trying to subtract from it, it will revert with arithmetic overflow / underflow.
This leaves the contract with funds that cannot be withdrawn. And the tokens are stuck forever.
Here is a link to the rETH contract where calculations are done described in the above steps:
https://etherscan.io/token/0xae78736cd615f374d3085123a210448e74fc6393#code#F6#L122
Stuck funds in the bridge contract
Manual review
Add a way to withdraw the stuck funds that can then be transferred to the TAPP/DAO.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.