Instant arbitrage opportunity through rETH and stETH price discrepancy
User can choose to withdraw their zETH to be a rETH or stETH, while in reality most user will choose the best return (highest value between rETH and stETH), instant arbitrage will happen and this will trigger pool imbalance, draining one over the other.\\nIn DittoETH, they accept two special types of Ethereum tokens: rETH and stETH. These tokens are based on regular ETH but are designed to stay close in value to one regular Ether. However, in reality, they can have slightly different values. rETH, stETH.\\nIn practice, when user want to withdraw, they can choose between rETH and stETH based on which one is worth more at that moment. The system doesn't really care which one you put in when a user first deposited their asset.\\nNow, here's where it gets interesting. Because rETH and stETH can have slightly different values, a savvy user could deposit the cheaper one, get a zeth, and then withdraw the more valuable rETH and stETH. a quick way to make some extra profit\\nAs we can see on line 110-112, the rETH or stETH withdrawn is depends on `ethAmount`, which from `_ethConversion` it's amount is 'equal' between rETH and stETH\\n```\\nFile: BridgeRouterFacet.sol\\n    function withdraw(address bridge, uint88 zethAmount)\\n        external\\n        nonReentrant\\n        onlyValidBridge(bridge)\\n    {\\n        if (zethAmount == 0) revert Errors.ParameterIsZero();\\n        uint88 fee;\\n        uint256 withdrawalFee = bridge.withdrawalFee();\\n        uint256 vault;\\n        if (bridge == rethBridge || bridge == stethBridge) {\\n            vault = Vault.CARBON;\\n        } else {\\n            vault = s.bridge[bridge].vault;\\n        }\\n        if (withdrawalFee > 0) {\\n            fee = zethAmount.mulU88(withdrawalFee);\\n            zethAmount -= fee;\\n            s.vaultUser[vault][address(this)].ethEscrowed += fee;\\n        }\\n        uint88 ethAmount = _ethConversion(vault, zethAmount);\\n        vault.removeZeth(zethAmount, fee);\\n        IBridge(bridge).withdraw(msg.sender, ethAmount);\\n        emit Events.Withdraw(bridge, msg.sender, zethAmount, fee);\\n    }\\n// rest of code\\n    function _ethConversion(uint256 vault, uint88 amount) private view returns (uint88) {\\n        uint256 zethTotalNew = vault.getZethTotal();\\n        uint88 zethTotal = s.vault[vault].zethTotal;\\n        if (zethTotalNew >= zethTotal) {\\n            // when yield is positive 1 zeth = 1 eth\\n            return amount;\\n        } else {\\n            // negative yield means 1 zeth < 1 eth\\n            return amount.mulU88(zethTotalNew).divU88(zethTotal);\\n        }\\n    }\\n```\\n
Consider to use oracle to adjust the price difference between rETH and stETH
Instant arbitrage opportunity through rETH and stETH price discrepancy, will also trigger imbalance between rETH and stETH pool.
```\\nFile: BridgeRouterFacet.sol\\n    function withdraw(address bridge, uint88 zethAmount)\\n        external\\n        nonReentrant\\n        onlyValidBridge(bridge)\\n    {\\n        if (zethAmount == 0) revert Errors.ParameterIsZero();\\n        uint88 fee;\\n        uint256 withdrawalFee = bridge.withdrawalFee();\\n        uint256 vault;\\n        if (bridge == rethBridge || bridge == stethBridge) {\\n            vault = Vault.CARBON;\\n        } else {\\n            vault = s.bridge[bridge].vault;\\n        }\\n        if (withdrawalFee > 0) {\\n            fee = zethAmount.mulU88(withdrawalFee);\\n            zethAmount -= fee;\\n            s.vaultUser[vault][address(this)].ethEscrowed += fee;\\n        }\\n        uint88 ethAmount = _ethConversion(vault, zethAmount);\\n        vault.removeZeth(zethAmount, fee);\\n        IBridge(bridge).withdraw(msg.sender, ethAmount);\\n        emit Events.Withdraw(bridge, msg.sender, zethAmount, fee);\\n    }\\n// rest of code\\n    function _ethConversion(uint256 vault, uint88 amount) private view returns (uint88) {\\n        uint256 zethTotalNew = vault.getZethTotal();\\n        uint88 zethTotal = s.vault[vault].zethTotal;\\n        if (zethTotalNew >= zethTotal) {\\n            // when yield is positive 1 zeth = 1 eth\\n            return amount;\\n        } else {\\n            // negative yield means 1 zeth < 1 eth\\n            return amount.mulU88(zethTotalNew).divU88(zethTotal);\\n        }\\n    }\\n```\\n