Missing checks on delegate calls allow for all public functions in MondrianWallet2
to be called via a delegate call. This is not possible in traditional EoAs. It breaks the intended functionality of MondrianWallet2
as described in its README.md
.
Description: MondrianWallet2:README.md
states that:
The wallet should be able to do anything a normal EoA can do, ...
Because it is not a smart contract, a normal EoA cannot have functions that are called via a delegate call. However, all public functions in MondrianWallet2
lack checks that disallow them to be called via a delegate call.
See the missing checks in the following functions:
function validateTransaction(bytes32, bytes32, Transaction memory _transaction) external payable requireFromBootLoader
function executeTransaction(bytes32, bytes32, Transaction memory _transaction) external payable requireFromBootLoaderOrOwner
function executeTransactionFromOutside(Transaction memory _transaction) external payable
function payForTransaction(bytes32, bytes32, Transaction memory _transaction) external payable
function prepareForPaymaster( bytes32, bytes32, Transaction memory ) external payable
Impact: The lack of checks disallowing functions to be called via a delegate call, breaking the intended functionality of MondrianWallet2
.
Recommended Mitigation: Create a modifier to check for delegate calls and apply this modifier to all public functions.
The mitigation below follows the example from DefaulAccount.sol
, written by Matter Labs (creator of ZKSync).
+ modifier ignoreInDelegateCall() {
+ address codeAddress = SystemContractHelper.getCodeAddress();
+ if (codeAddress != address(this)) {
+ assembly {
+ return(0, 0)
+ }
+ }
+
+ _;
+ }
.
.
.
+ function validateTransaction(bytes32, /*_txHash*/ bytes32, /*_suggestedSignedHash*/ Transaction memory _transaction) external payable requireFromBootLoader ignoreInDelegateCall
- function validateTransaction(bytes32, /*_txHash*/ bytes32, /*_suggestedSignedHash*/ Transaction memory _transaction) external payable requireFromBootLoader
.
.
.
+ function executeTransaction(bytes32, /*_txHash*/ bytes32, /*_suggestedSignedHash*/ Transaction memory _transaction) external payable requireFromBootLoaderOrOwner ignoreInDelegateCall
- function executeTransaction(bytes32, /*_txHash*/ bytes32, /*_suggestedSignedHash*/ Transaction memory _transaction) external payable requireFromBootLoaderOrOwner
.
.
.
+ function executeTransactionFromOutside(Transaction memory _transaction) external payable ignoreInDelegateCall
- function executeTransactionFromOutside(Transaction memory _transaction) external payable
.
.
.
+ function payForTransaction(bytes32, /*_txHash*/ bytes32, /*_suggestedSignedHash*/ Transaction memory _transaction) external payable ignoreInDelegateCall
- function payForTransaction(bytes32, /*_txHash*/ bytes32, /*_suggestedSignedHash*/ Transaction memory _transaction) external payable
.
.
.
+ function prepareForPaymaster( bytes32, /*_txHash*/ bytes32, /*_possibleSignedHash*/ Transaction memory /*_transaction*/ ) external payable ignoreInDelegateCall
- function prepareForPaymaster( bytes32, /*_txHash*/ bytes32, /*_possibleSignedHash*/ Transaction memory /*_transaction*/ ) external payable