Currently the protocol assumes that the MOR tokens will be minted to the correct user address. This is not true for all cases:
If the user is a Multisig (Contract Account), the same address on the destination chain (Arbitrum) might not be controlled/owned by the same user.
If the user is a contract/dapp, the same address on the destination chain is not controlled/owned by the same user.
MOR tokens would be minted to an address not owned by the user, leading to loss of funds.
Here is the whole process:
Let us understand how MOR tokens would be lost
The user (i.e. using multisig/contract/dapp) calls the claim() function below by passing in the poolId_
and user_
(user's address).
Consider the function works as expected from Lines 156-172 (this is independent of the issue)
On Line 176, the function sendMintMessage() is called on the L1Sender.sol contract with user_, the pending rewards (amount of MOR that will be minted) and the refund address (user_ is the msg.sender).
In function sendMintMessage(), the following occurs:
On Line 129, the user_ and the pending rewards amount is encoded into bytes memory payload variable.
On Line 132, the send() function is called on the LayerZero endpoint contract
After the send() function call, LayerZero relays the cross-chain transaction to call the receivePayload() function on the Endpoint contract (Arbitrum), which ultimately calls the lzReceive() function on the L2MessageReceiver.sol contract.
On Line 40, function _blockingLzReceive() is called internally.
Function _blockingLzReceive() calls the nonBlockingLzReceive() function here, which ultimately calls the function _nonBlockingLzReceive() here.
In function _nonBlockingLzReceive() here, the following occurs:
Lines 97 to 103, the function checks the source id and sender are correct.
On Line 105, the payload is decoded to variables user_ and amount_.
On Line 107, the mint() function is called on the MOR token contract on Arbitrum to mint tokens to the user_. But since the user_ address on the destination chain is not owned by the actual user, the MOR tokens would be sent to someone else or no one in case the address is not being used. This would mean permanent loss of MOR tokens for the user.
Through this we can see how the issue arises.
Manual Review
Similar issues were also found in the C4 Maia contest:
Encode an extra address field into the payload on the source chain. This address field would be the recipient of the MOR tokens on the destination chain.
Additionally, note that the claim() function currently allows anyone to call claim() on behalf of any user since the user_ address is taken in as a parameter (see here). Make sure to remove this user_ parameter and use msg.sender instead so that an attacker cannot provide his own recipient address and call claim() on user's behalf.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.