DittoETH

Ditto
DeFiFoundryOracle
55,000 USDC
View results
Submission Details
Severity: low
Valid

`ZETH` protocol derivative assumes a `~1=1` peg of stETH to ETH

Vulnerability Details

  • The protocol implements the ETH derivative for the Lido protocol. The stETH token is the liquid representation of the ETH staked in this protocol.

  • the BridgeSteth contrat is assuming a peg of 1 ETH ~= 1 stETH.

function deposit(address from, uint256 amount) external onlyDiamond returns (uint256) {
// Transfer stETH to this bridge contract
// @dev stETH uses OZ ERC-20, don't need to check success bool
steth.transferFrom(from, address(this), amount);
return amount;
}
  • Even though both tokens have a tendency to keep the peg, this hasn't been always the case as it can be seen in this dashboard. There have been many episodes of market volatility that affected the price of stETH, notably the one in last June when stETH traded at ~0.93 ETH.

  • a user can deposit stETH to the system and get a virtual balance of ZETH Derivative that stands for ETH by approving stETH to the bridge contract. then calling the function deposit() from BridgeRouterFacet.

function deposit(address bridge, uint88 amount) external nonReentrant onlyValidBridge(bridge) {
if (amount < Constants.MIN_DEPOSIT) revert Errors.UnderMinimumDeposit();
// @dev amount after deposit might be less, if bridge takes a fee
uint88 zethAmount = uint88(IBridge(bridge).deposit(msg.sender, amount)); // @dev(safe-cast)
uint256 vault;
if (bridge == rethBridge || bridge == stethBridge) {
vault = Vault.CARBON;
} else {
vault = s.bridge[bridge].vault;
}
vault.addZeth(zethAmount);
maybeUpdateYield(vault, zethAmount);
emit Events.Deposit(bridge, msg.sender, zethAmount);
}
  • the user passes the bridge address. which in this case BridgeSteth and the amount wanna deposit.

  • this function calls the bridge that the user provided and the bridge get the tokens from the user. and return the amount getted from the user.

  • then The protocol increases the virtual balance of the user in the system by the same amount of stETH the user deposited . in the function addZeth from LibVault.

function addZeth(uint256 vault, uint88 amount) internal {
AppStorage storage s = appStorage();
s.vaultUser[vault][msg.sender].ethEscrowed += amount;
s.vault[vault].zethTotal += amount;
}
  • the user then can withdraw this Zeth virtuals balance through any bridge in this vault. and in our case we have two bridges in this vault. the RethBridge and stETHBridge.

  • no the vulnerability arises when for example as we said the price of stETH is less than ETH then a malicious user can create a massive profit from that. by depositing stETH and withdrawing REth through RethBridge. since the protocole don't Differentiate between the two since they are in the same vault you can deposits with any bridge and withdraw with any bridge you want.

Impact

The protocol's vulnerability allows malicious users to exploit price disparities between stETH and ETH. By depositing undervalued stETH and withdrawing overvalued Reth through different bridges within the same vault, these users can generate substantial profits, posing a significant financial risk to the protocol.

Tools Used

manual review

Updates

Lead Judging Commences

0xnevi Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-579

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.