The Soulmate::mintSoulmateToken function mints an ERC721 token without the necessary checks to ensure that the receiver of a minted token can handle ERC721 tokens, which could lead to tokens being locked in the contract that do not support the ERC721 token interface.
The Soulmate contract is an ERC721 token designed to represent soulmate pairings. The Soulmate::mintSoulmateToken function mints a new token when two soulmates are reunited. The contract is intended to be soulbound, meaning that tokens cannot be transferred after minting. For a token minting the function uses ERC721::_mint function.
The implementation of the _mint function is the following:
We can see that the _mint function doesn't perform a check if the account to mint the NFT to is a smart contract that can handle ERC721 tokens. So tokens can be minted to non-ERC721 receivers.
The ERC721 standard includes an optional extension for safe transfers, which requires that the receiving contract implements the onERC721Received function. This function must return a value to indicate that the contract can handle ERC721 tokens. If the receiving contract does not return this value, the transfer should be reverted.
The ERC721::_mint function does not perform this check, which means that if a token is minted to a contract address that does not implement the onERC721Received function, the token could become permanently locked within that contract.
The absence of the ERC721 receiver check poses a high risk of token loss if a token is minted to a contract that cannot handle ERC721 tokens.
The test function test_failIfCallerCanNotReceiveERC721Token shows that the Soulmate::mintSoulmateToken function doesn't revert when the contract address badReceiver (the address can not receive ERC721 token) is calling the Soulmate::mintSoulmateToken.
Manual Review
Use ERC721::_safeMint function instead of ERC721::_mint function. But add a nonReentrant modifier and follow the checks-effects-interactions pattern in Soulmate::mintSoulmateToken function, because the onERC721Received callback in the _safeMint function introduces a reentrancy vector.
Low severity, - If a user utilizes an EOA, the check is not required. - If a user utilizes a contract that they own to mint soulmate tokens, than check is required. However, this would rely on user error minting. Since there is no mention that ownership of token must be from EOAs, I believe low severity is appropriate.
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.