CertiK reviewed unshETH (UnshETH #2) on 4 Apr 2023: 7 findings, 0 critical; 5 marked fixed, 2 acknowledged.
Report hosted on skynet.certik.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 1 |
| Medium | 0 | 0 | 1 |
| Low | 0 | 2 | 3 |
The `payable` keyword is missing from the `sgReceive()` function, making it impossible to receive ETH and pay the gas fee to execute the function `IOFTCore(proxyUnshethAddress).sendFrom` to send the unshETH back to `_toAddr` on BSC. ```solidity IOFTCore(proxyUnshethAddress).sendFrom{value:unsheth_gas_cost}( //TODO really think about this address(this), //current owner of the unsheth _chainId, //chain Id where the proxy of the unsheth exists (we recieve this in sgRecieve) abi.encode(toAddr), //the address we want the unsheth to end up in unshethMinted, //the amount of unsheth to send payable(address(this)), //the refund address if something goes wrong or excess address(0x0), //the ZRO Payment Address abi.encode("") //Adapter Params //TODO check on this ); ```
After adding the first `_lsd`, the `lsdIndex[_lsd]` variable retains its initial value of 0 since the length of the `supportedLSDs` array is 1. Consequently, if the same `_lsd` is added again, the `require` statement in the `addLSD` function will evaluate to true, causing the `lsdIndex[_lsd]` variable can be overwritten. ```solidity=194 function addLSD(address _lsd) public onlyOwner onlyWhenPaused { require(lsdIndex[_lsd] == 0, "Lsd has already been added"); //fyi fails on the first lsd being duplicated since it has actual index 0 supportedLSDs.push(_lsd); lsdIndex[_lsd] = supportedLSDs.length-1; //reverse mapping of supportedLSDs indices isEnabled[_lsd] = false; lsdConfigs[_lsd] = LSDConfig(0, 0, 0); emit LSDAdded(_lsd); } ``` ```solidity=448 function exit(uint256 amount) external nonReentrant { require(migrated = false, "Already migrated, use v2 vault to exit"); require(block.timestamp > shanghaiTime, "Cannot exit until shanghaiTime"); require(!withdrawalsPaused || block.timestamp > withdrawalUnpauseTime, "Withdrawals are paused"); require(IERC20(unshETHAddress).balanceOf(msg.sender) >= amount, "Insufficient unshETH"); uint256 shareOfUnsheth = 1e18*amount/IERC20(unshETHAddress).totalSupply(); uint256 fee = shareOfUnsheth*redeemFee/10000; //redeem fees are 100% retained by remaining unshETH holders IunshETH(unshETHAddress).minter_burn_from(msg.sender, amount); for (uint256 i = 0; i < supportedLSDs.length; i = unchkIncr(i)) { uint256 lsdBalance = IERC20(supportedLSDs[i]).balanceOf(address(this)); uint256 amountPerLsd = (shareOfUnsheth-fee)*lsdBalance/1e18; IERC20(supportedLSDs[i]).safeTransfer(msg.sender, amountPerLsd); } } ```
As per the validation of `_newTime` below, the variable `shanghaiTime` can be updated when `block.timestamp` < `_newTime` < `shanghaiTime` + 4 weeks. ```solidity=530 function updateShanghaiTime(uint256 _newTime) external onlyOwnerOrAdmin { require(_newTime < shanghaiTime + 4 weeks, "Cannot extend more than 4 weeks" ); require(_newTime > block.timestamp, "Cannot set shanghaiTime in the past" ); shanghaiTime = _newTime; emit ShanghaiTimeUpdated(shanghaiTime); } ``` However, if the `block.timestamp` >= `shanghaiTime` + 4weeks, there is no way to set the `_newTime` as the `shanghaiTime` no matter what the `_newTime` is.
There is a function `setVdAmm` which only changes the `swapperAddress` and `ammEnabled`. However, we can not find any usage of the `swapperAddress` and `ammEnabled`. We would like the team to elaborate more about the usages of the `swapperAddress` and `ammEnabled`.
Using Solidity's `transfer()` and `send()` functions for transferring Ether is not recommended, since some contracts may not be able to receive the funds. These functions forward only a fixed amount of gas (2300 specifically) and the receiving contracts may run out of gas before finishing the transfer. Additionally, gas costs may increase in the future. Thus, some contracts that can receive now may stop working in the future due to the gas limitation.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (7)
1,044 projects reviewed · 1,375 reports · latest May 2025
See CertiK’s auditsSomething wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us