Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: medium
Valid

Lack of ERC721 Token Receipt Verification in Huff Smart Contract

Summary

The provided Huff smart contract implements an NFT minting function similar to the ERC721 standard but lacks the necessary checks to ensure that the recipient address can correctly handle the receipt of an ERC721 token. This omission can lead to tokens being permanently locked if they are sent to a contract that does not implement the onERC721Received() function as specified in the ERC721 standard.

Vulnerability Details

The vulnerability arises from the absence of a check to confirm that the recipient contract has a properly implemented onERC721Received() function. This function is a hook that is called on the recipient contract upon the transfer of an ERC721 token, allowing the contract to handle or reject the transfer.

Impact

If an ERC721 token is transferred to a contract that does not have the onERC721Received(), the token transfer will still be considered successful by the smart contract. This can result in the token being locked within the recipient contract with no way to retrieve it, effectively rendering the token unusable and potentially causing financial loss to the token owner.

Tools Used

Manual review

Recommendations

To mitigate this vulnerability, the smart contract should be updated to include a check that calls the onERC721Received() function on the recipient contract during the minting process. If the recipient is a contract, the minting function should only proceed if the call to onERC721Received() is successful and returns the expected magic value. If the recipient is an externally owned account (EOA), this check can be skipped. The resolution involves implementing a new macro in the Huff code that performs this check and integrating it into the minting logic. If the check fails, the contract should revert the transaction to prevent the token from being locked in an incompatible contract.

#define constant ERC721_RECEIVED = 0x150b7a02
#define macro CHECK_ON_ERC721_RECEIVED() = takes (3) returns (1) {
// Input stack: [to, tokenId, operator]
// Check if 'to' is a contract
dup1 is_contract jumpi
// If 'to' is not a contract, return true (0x01)
0x01 swap3 pop pop jump
// If 'to' is a contract, call 'onERC721Received' on it
is_contract:
// Prepare call data for 'onERC721Received'
// Selector for 'onERC721Received(address,address,uint256,bytes)'
0x80 0x00 mstore // [free_mem_ptr]
0x150b7a02 0x80 mstore // [selector, free_mem_ptr]
caller 0x84 mstore // [operator, selector, free_mem_ptr]
dup3 0x94 mstore // [to, operator, selector, free_mem_ptr]
dup2 0xa4 mstore // [tokenId, to, operator, selector, free_mem_ptr]
0xa0 0x00 mstore // [data_length, tokenId, to, operator, selector, free_mem_ptr]
// Perform the call to 'onERC721Received'
dup1 0x80 0xa4 0x00 gas call
// Check if the call was successful and the return value is the magic value
iszero invalid_receiver jumpi
returndatasize 0x20 lt invalid_receiver jumpi
0x00 returndatacopy
0x00 mload ERC721_RECEIVED eq
invalid_receiver jumpi
// Return true (0x01) if the magic value matches
0x01 swap3 pop pop jump
// Handle invalid receiver
invalid_receiver:
// Return false (0x00) if the receiver contract did not handle the token correctly
0x00
}
#define macro _MINT() = takes (2) returns (0) {
// ... existing minting logic ...
// Give tokens to the recipient.
TRANSFER_GIVE_TO() // [from (0x00), to, tokenId]
// Check if the recipient can handle ERC721 tokens
CHECK_ON_ERC721_RECEIVED() // [success]
iszero invalid_receiver jumpi
// Emit the transfer event.
__EVENT_HASH(Transfer) // [sig, from (0x00), to, tokenId]
0x00 0x00 log4 // []
// Continue Executing
cont jump
invalid_receiver:
// Handle the case where the recipient cannot receive ERC721 tokens
// Revert or take other appropriate action
// ...
// ...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Components of ERC721 not properly (or at all) implemented in HUFF

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.