Special Caramel Loris
Medium
The L2ERC1155Gateway contract may fail to mint ERC1155
tokens when finalizing deposits if the recipient address _to
is a contract that does not implement the IERC1155Receiver
interface. This issue can cause transaction reversion on Layer 2 (L2), resulting in tokens not being minted on L2 and potentially locking funds on Layer 1 (L1).
In the L2ERC1155Gateway contract, the functions finalizeDepositERC1155 and finalizeBatchDepositERC1155 are responsible for minting ERC1155 tokens on L2 when a deposit is finalized. These functions call the mint or batchMint methods of the ERC1155 token contract (IMorphERC1155):
IMorphERC1155(_l2Token).mint(_to, _tokenId, _amount, "");
When tokens are minted or transferred to a contract address, a safe transfer check is performed by calling _doSafeTransferAcceptanceCheck
. This function invokes onERC1155Received
on the recipient contract:
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
If the recipient contract (_to)
does not implement the IERC1155Receiver
interface and the onERC1155Received
function, the safe transfer acceptance check fails, causing the entire transaction to revert.
Why This Is a Problem?:
- Reverting the transaction means that the minting process fails, and the tokens are not minted on L2.
- The user's tokens remain on L1, but since the corresponding minting on L2 failed, the user cannot access their funds on L2.
- Users depositing tokens to contracts not compatible with
IERC1155Receiver
may lose access to their assets without an obvious cause.
Users may be unable to access their tokens on L2 after deposit because a reversion could result in the ERC1155 tokens becoming stuck in the L1 gateway
/// @inheritdoc IL2ERC1155Gateway
function finalizeDepositERC1155(
address _l1Token,
address _l2Token,
address _from,
address _to,
uint256 _tokenId,
uint256 _amount
) external virtual onlyCallByCounterpart nonReentrant {
require(_l1Token != address(0), "token address cannot be 0");
require(_l1Token == tokenMapping[_l2Token], "l2 token mismatch");
IMorphERC1155(_l2Token).mint(_to, _tokenId, _amount, "");
emit FinalizeDepositERC1155(_l1Token, _l2Token, _from, _to, _tokenId, _amount);
}
/// @inheritdoc IL2ERC1155Gateway
function finalizeBatchDepositERC1155(
address _l1Token,
address _l2Token,
address _from,
address _to,
uint256[] calldata _tokenIds,
uint256[] calldata _amounts
) external virtual onlyCallByCounterpart nonReentrant {
require(_l1Token != address(0), "token address cannot be 0");
require(_l1Token == tokenMapping[_l2Token], "l2 token mismatch");
IMorphERC1155(_l2Token).batchMint(_to, _tokenIds, _amounts, "");
emit FinalizeBatchDepositERC1155(_l1Token, _l2Token, _from, _to, _tokenIds, _amounts);
}
Manual Review
Before minting, check if the recipient address _to
is a contract and whether it implements the IERC1155Receiver
interface. This can prevent transaction reversion due to incompatible recipient contracts.
Ideally, in the future, a system should be implemented to check the Merkle tree and recover the ERC1155 tokens if the message fails on L2.