DittoETH

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

Missing zero address validations

Summary

Missing zero address validations is detected in smart contracts BridgeReth.sol and BridgeSteth.sol.

Vulnerability Details

In contract BridgeReth.sol the input parameter from in the function deposit(), the input parameter to in function withdraw() and the input parameter to in function unstake() are not checked if they are zero addresses. Also, the input parameter to in function unstake() should be checked if it is a valid address, because it is used in low-level function call.

In contract BridgeSteth.sol the input parameter from in the function deposit(), the input parameter to in function withdraw() and the input parameter to in function unstake() are not checked if they are zero addresses.

Impact

It is a good practice to check if the input addresses are zero addresses. This is because the zero address is often used as a default value in Solidity, and sending tokens to this address will effectively burn them, as they cannot be recovered. Consider adding a requirement to prevent this.
Also, the account existance in function unstake() should be checked, the documentation says:

"The low-level functions call, delegatecall and staticcall return true as their first return value if the account called is non-existent, as part of the design of the EVM. Account existence must be checked prior to calling if needed."

https://docs.soliditylang.org/en/latest/control-structures.html

Tools Used

Manual review, VS Code

Recommendations

Add require() to validate the address parameters in functions deposit(), withdraw() and unstake() in contracts BridgeReth.sol and BridgeSteth.sol. Also, in function unstake() in BridgeReth.sol add check to ensure that the address to exists.

In BridgeReth.sol:

function deposit(address from, uint256 amount)
external
onlyDiamond
returns (uint256)
{
require(from != address(0), "from address cannot be the zero address");
IRocketTokenRETH rocketETHToken = _getRethContract();
// Transfer rETH to this bridge contract
// @dev RETH uses OZ ERC-20, don't need to check success bool
rocketETHToken.transferFrom(from, address(this), amount);
// Calculate rETH equivalent value in ETH
return rocketETHToken.getEthValue(amount);
}
function withdraw(address to, uint256 amount)
external
onlyDiamond
returns (uint256)
{
require(to != address(0), "to address cannot be the zero address");
IRocketTokenRETH rocketETHToken = _getRethContract();
// Calculate zETH equivalent value in rETH
uint256 rethValue = rocketETHToken.getRethValue(amount);
// Transfer rETH from this bridge contract
// @dev RETH uses OZ ERC-20, don't need to check success bool
rocketETHToken.transfer(to, rethValue);
return rethValue;
}
function unstake(address to, uint256 amount) external onlyDiamond {
require(to != address(0), "to address cannot be the zero address");
uint32 size;
assembly {
size := extcodesize(to)
}
require(size > 0, "to is not a valid contract address");
IRocketTokenRETH rocketETHToken = _getRethContract();
uint256 rethValue = rocketETHToken.getRethValue(amount);
uint256 originalBalance = address(this).balance;
rocketETHToken.burn(rethValue);
uint256 netBalance = address(this).balance - originalBalance;
if (netBalance == 0) revert NetBalanceZero();
(bool sent,) = to.call{value: netBalance}("");
assert(sent);
}

In BridgeSteth.sol:

function deposit(address from, uint256 amount)
external
onlyDiamond
returns (uint256)
{
require(from != address(0), "from address cannot be the zero address");
// 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;
}
function withdraw(address to, uint256 amount)
external
onlyDiamond
returns (uint256)
{
require(to != address(0), "from address cannot be the zero address");
// @dev stETH uses OZ ERC-20, don't need to check success bool
steth.transfer(to, amount);
return amount;
}
function unstake(address to, uint256 amount) external onlyDiamond {
require(to != address(0), "from address cannot be the zero address");
uint256[] memory amountArray = new uint256[](1);
amountArray[0] = amount;
uint256 requestId = unsteth.requestWithdrawals(amountArray, address(this))[0];
unsteth.safeTransferFrom(address(this), to, requestId);
}
Updates

Lead Judging Commences

0xnevi Lead Judge
almost 2 years ago
0xnevi Lead Judge almost 2 years ago
Submission Judgement Published
Invalidated
Reason: Zero address checks

Support

FAQs

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