Open code423n4 opened 1 year ago
IMO, should be considered as high quality report!
L
L
Disputing as I think it's ok to check that the developer set the value and it will never run in prod
Check for address(0) already awarded in L-1
NC
NC
NC
NC
NC
2L 5NC
GalloDaSballo marked the issue as grade-a
QA Report
L-1: should check the address(0)
L1ERC20Bridge#deposit
In the zkSync, the address of ETH is set like this.
And
L1EthBridge#deposit
checks thetokenAddress
isCONVENTIONAL_ETH_ADDRESS
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1EthBridge.sol#L32-L33
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1EthBridge.sol#L88-L93
The
L1ERC20Bridge#deposit
has no checks thetokenAddress
is notCONVENTIONAL_ETH_ADDRESS
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1ERC20Bridge.sol#L111-L117The
safeTransferFrom()
by OpenZeppelin will return revert in this case. However, you should prevent this issue like this.L-2: Can be overflow
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/common/libraries/UncheckedMath.sol
The
unchecked
keyword can set the default overflow and underflow checks to off. This is used to optimize the gas cost but there are no overflow checks so, it happens to overflow silently.Therefore, you should add checking to prevent overflow or add a comment.
e.g) โBe sure to check overflow before using this libraryโ
L-3:
require()
should be used instead ofassert()
๐ Description
Prior to solidity version 0.8.0, hitting an assert consumes the remainder of the transaction's available gas rather than returning it, as
require()
/revert()
do.assert()
should be avoided even past solidity version 0.8.0 as its documentation states that The assert function creates an error of type Panic(uint256). ... Properly functioning code should never create a Panic, not even on invalid external input. If this happens, then there is a bug in your contract which you should fix๐ก Recommendation
You should change from
assert()
torequire()
๐ Findings:
2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/DiamondCut.sol#L16
assert(SECURITY_COUNCIL_APPROVALS_FOR_EMERGENCY_UPGRADE > 0);L-4: should add checking return value by
readAddress()
L1EthBridge.sol
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1EthBridge.sol#L214-L228
L1ERC20Bridge.sol
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1ERC20Bridge.sol#L225-L257
L1EthBridge.sol
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1EthBridge.sol#L182-L211
L1ERC20Bridge.sol
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1ERC20Bridge.sol#L260-L279
๐ Description
If the return value of
_parseL2WithdrawalMessage()
is as follows, the amount canโt withdraw forever(address l1Receiver, uint256 amount) = (address(0), 100000)
Therefore, you should add checking to prevent this case
๐ก Recommendation
L1EthBridge.sol
L1ERC20Bridge.sol
N-1: Open Todos
๐ Description
Code architecture, incentives, and error handling/reporting questions/issues should be resolved before deployment
๐ก Recommendation
Delete TODO keyword
๐ Findings:
2022-10-zksync/blob/main/ethereum/contracts/zksync/Config.sol#L28
// TODO: change constant to the real root hash of empty Merkle tree (SMA-184)2022-10-zksync/blob/main/ethereum/contracts/zksync/Plonk4VerifierWithAccessToDNext.sol#L43
PairingsBn254.Fr[1] state_polys_openings_at_z_omega; // TODO: not use array while there is only D_next2022-10-zksync/blob/main/ethereum/contracts/zksync/Plonk4VerifierWithAccessToDNext.sol#L224
require(proof.state_polys_openings_at_z_omega.length == 1); // TODO2022-10-zksync/blob/main/ethereum/contracts/zksync/Plonk4VerifierWithAccessToDNext.sol#L304
// require(vk.num_inputs > 0); // TODO2022-10-zksync/blob/main/ethereum/contracts/zksync/Plonk4VerifierWithAccessToDNext.sol#L308
// TODO we may use batched lagrange compputation2022-10-zksync/blob/main/ethereum/contracts/zksync/Plonk4VerifierWithAccessToDNext.sol#L454
t.mul_assign(vk.non_residues[i - 1]); // TODO add one into non-residues during codegen?2022-10-zksync/blob/main/ethereum/contracts/zksync/Plonk4VerifierWithAccessToDNext.sol#L485
// TODO2022-10-zksync/blob/main/ethereum/contracts/zksync/Verifier.sol#L132
// require(serialized_proof.length == 44); TODO2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/Mailbox.sol#L94
// TODO: estimate gas for L1 execute2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/Mailbox.sol#L127
// TODO: Restore after stable priority op fee modeling. (SMA-1230)2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/Mailbox.sol#L169
layer2Tip: uint192(0) // TODO: Restore after fee modeling will be stable. (SMA-1230)2022-10-zksync/blob/main/ethereum/contracts/zksync/interfaces/IExecutor.sol#L56
/// TODO: The verifier integration is not finished yet, change the structure for compatibility later2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/PairingsBn254.sol#L208
// TODON-2: No use of two-phase ownership transfers
๐ Description
Consider adding a two-phase transfer, where the current owner nominates the next owner, and the next owner has to call
accept*()
to become the new owner. This prevents passing the ownership to an account that is unable to use it.๐ก Recommendation
Consider implementing a two step process where the admin nominates an account and the nominated account needs to call an acceptOwnership() function for the transfer of admin to fully succeed. This ensures the nominated EOA account is a valid and active account.
๐ Findings:
2022-10-zksync/blob/main/ethereum/contracts/common/AllowList.sol#L34
owner = _owner;2022-10-zksync/blob/main/ethereum/contracts/common/AllowList.sol#L158
owner = newOwner;N-3: Use
string.concat()
orbytes.concat()
๐ Description
Solidity version 0.8.4 introduces
bytes.concat()
(vsabi.encodePacked(<bytes>,<bytes>)
)Solidity version 0.8.12 introducesstring.concat()
(vsabi.encodePacked(<str>,<str>)
)๐ก Recommendation
Use concat instead of abi.encodePacked
๐ Findings:
2022-10-zksync/blob/main/ethereum/contracts/common/libraries/UnsafeBytes.sol#L7
* @dev The library provides a set of functions that help read data from an "abi.encodePacked" byte array.2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/Executor.sol#L283
abi.encodePacked(2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/Executor.sol#L364
abi.encodePacked(2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/Executor.sol#L373
return abi.encodePacked(s.zkPorterIsAvailable, s.l2BootloaderBytecodeHash, s.l2DefaultAccountBytecodeHash);2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/Mailbox.sol#L59
abi.encodePacked(_log.l2ShardId, _log.isService, _log.txNumberInBlock, _log.sender, _log.key, _log.value)2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/TranscriptLib.sol#L29
self.state_0 = keccak256(abi.encodePacked(DST_0, old_state_0, self.state_1, value));2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/TranscriptLib.sol#L30
self.state_1 = keccak256(abi.encodePacked(DST_1, old_state_0, self.state_1, value));2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/TranscriptLib.sol#L43
bytes32 query = keccak256(abi.encodePacked(DST_CHALLENGE, self.state_0, self.state_1, self.challenge_counter));2022-10-zksync/blob/main/zksync/contracts/bridge/L2ERC20Bridge.sol#L109
return abi.encodePacked(IL1Bridge.finalizeWithdrawal.selector, _to, _l1Token, _amount);2022-10-zksync/blob/main/zksync/contracts/bridge/L2ETHBridge.sol#L75
return abi.encodePacked(IL1Bridge.finalizeWithdrawal.selector, _to, _amount);N-4: Empty Revert
If returns revert, you should add comment to makes failed points clear
https://github.com/code-423n4/2022-10-zksync/blob/main/zksync/contracts/bridge/L2StandardERC20.sol#L116
https://github.com/code-423n4/2022-10-zksync/blob/main/zksync/contracts/bridge/L2StandardERC20.sol#L122
https://github.com/code-423n4/2022-10-zksync/blob/main/zksync/contracts/bridge/L2StandardERC20.sol#L128
N-5: 404 Links
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/common/ReentrancyGuard.sol#L19 This is invalid link https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]
This is valid link https://blog.openzeppelin.com/reentrancy-after-istanbul/
You should change as follows